You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@poi.apache.org by Sumedh <su...@gmail.com> on 2014/12/14 08:35:24 UTC

Using MapDB to reduce memory footprint of shared strings table in SXSSF

Hi,

We are using POI SXSSF for writing excel files. We faced heap memory usage
issues with large excels containing large amounts of text data.

Currently, SXSSF stores the shared strings table completely in memory, and
if shared strings table is not used, the xlsx file is not compatible with
some clients (like iPad) (
https://issues.apache.org/bugzilla/show_bug.cgi?id=53130).

We tried using MapDB to store shared strings table, which flushes entries
to disk if there are a large number of entries. It's working quite well,
and successfully writes large files where POI currently throws OOM error.

PFA the modified files along with some test cases. The code is very crude
right now.

What is a good option to use this kind of code by extending existing
classes, instead of patching original code? Ideally, we would like to
extend SharedStringTable and plug it in.

Of course it would be awesome if something like this becomes available in
POI directly. Not sure if you'll be OK to depend on MapDB, or would like
your own code.

-- 
Cheers,
Sumedh
http://www.linkedin.com/in/sumedhinamdar
Ph: +91 - 95610 99125

Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Alex Geller <ag...@4js.com>.
>I seem to have a slightly older copy of the file format docs on my laptop,
but in that one (iso29500_Part1.pdf - ISO/IEC 29500-1:2008(E)) there's a
section 18.4 entitled "Shared String Table" within the "SpreadsheetML
Reference Material" area.

Very good, I am reading it now (@Sureh: Download this:
http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-376,%20Fourth%20Edition,%20Part%201%20-%20Fundamentals%20And%20Markup%20Language%20Reference.zip).

Thanks a lot, I will come back when I have looked into this more deeply.
Regards,
Alex




--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Using-MapDB-to-reduce-memory-footprint-of-shared-strings-table-in-SXSSF-tp5717375p5717399.html
Sent from the POI - Dev mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
For additional commands, e-mail: dev-help@poi.apache.org


Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Nick Burch <ap...@gagravarr.org>.
On Mon, 15 Dec 2014, Alex Geller wrote:
> I think that the job of interning strings can be abstracted in a simple 
> way (A function or two) so that we can worry about the implementation 
> later (My implementation is perhaps attractive because it is simple, it 
> has a reasonable performance and can be activated on a threshold basis 
> so that no option to switch it on or off is needed but I am OK with any 
> other implementation too).

If we could do it in such a way that people using XSSF, SXSSF and 
SAX+Helpers are all able to use it, that'd be great! If it's SXSSF only, 
that's not the end of the world. Having pluggable implementations behind 
an interface is probably the best way, if possible

> My problem (And I think that Sumedh is perhaps struggling with the same 
> issue) is some guidance on how to go about this. We can just look at the 
> patch that was made for the support of shared strings which apparently 
> shares a lot of code witch XSSF and ask ourselves how to make that code 
> use less memory but I suspect that we could perhaps do a much better job 
> if we really understood why the code is the way it is.

"svn log" and "svn blame" are your best bet for the why. On the whole, 
it's whatever worked best at the time support was added!

> I would like to have answers to the question like "What are all the 
> other fields in the CTRst class for? Is there a documentation from 
> Microsoft or ECMA that covers this point? Can you point me to the 
> documentation that handles the string externalizing?

I seem to have a slightly older copy of the file format docs on my laptop, 
but in that one (iso29500_Part1.pdf - ISO/IEC 29500-1:2008(E)) there's a 
section 18.4 entitled "Shared String Table" within the "SpreadsheetML 
Reference Material" area. That looks to be a pretty good guide to the 
different kinds of things you can find in the shared strings table

Nick

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
For additional commands, e-mail: dev-help@poi.apache.org


Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Alex Geller <ag...@4js.com>.
If I remember correctly then I had a look at that before I set out to do my
own experiments and I didn't find something that seemed to match perfectly.
However I can do that again and perhaps ask advice from the people over
there but I don't think that this is the main issue here.

I think that the job of interning strings can be abstracted in a simple way
(A function or two) so that we can worry about the implementation later (My
implementation is perhaps attractive because it is simple, it has a
reasonable performance and can be activated on a threshold basis so that no
option to switch it on or off is needed but I am OK with any other
implementation too).

My problem (And I think that Sumedh is perhaps struggling with the same
issue) is some guidance on how to go about this.
We can just look at the patch that was made for the support of shared
strings which apparently shares
a lot of code witch XSSF and ask ourselves how to make that code use less
memory but I suspect that
we could perhaps do a much better job if we really understood why the code
is the way it is.

I would like to have answers to the question like "What are all the other
fields in the CTRst class
for? Is there a documentation from Microsoft or ECMA that covers this point?
Can you point me to the documentation that handles the string externalizing?
Looking at the files that Excel produces, things look so straightforward
that it seems feasible to rewrite the interning in a few dozen lines. Very
likely it isn't but I would like to know why.  
Thanks,
Alex




--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Using-MapDB-to-reduce-memory-footprint-of-shared-strings-table-in-SXSSF-tp5717375p5717381.html
Sent from the POI - Dev mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
For additional commands, e-mail: dev-help@poi.apache.org


Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Nick Burch <ap...@gagravarr.org>.
On Mon, 15 Dec 2014, Alex Geller wrote:
> The next thing I explored was doing string interning on disk.
> I tried three methods:
> 1) By trie (An unoptimized radix tree)
> 2) By B-Tree
> 3) By a disk hash map
>
> I benchmarked these 3 and it turned out that the hash gave the best
> performance (I will share the code with anyone interested upon request)
> Normally B-Trees are very good but since the strings do not have a fixed
> length we need an extra indirection to a string table and that ruins the
> performance (Minimizing the number of seeks is crucial for the performance).

It's probably worth asking the Apache Lucene community for advice on this. 
If someone will have exhaustively tested the best ways to store and 
retrieve blocks of test to disk and memory, under an Apache license, it'll 
be that lot!

(They have quite a number of storage related code, which can be plugged in 
as needed, along with advice on what to use where, so we might be able to 
take a class or two that they recommend and use that for people with very 
large strings tables)

Nick

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
For additional commands, e-mail: dev-help@poi.apache.org


Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Alex Geller <ag...@4js.com>.
Hi,
I am glad that you are raising this subject since I had a prophylactic look
into this a while back.

If I understand you correctly the your concern is that the shared
strings table currently used in SXSSF can exhaust memory.

Let me sketch out what I have done so far on this topic (It's been a
while so I might be inaccurate on some details).

The current implementation stores shares strings in a HashMap. This can
exhaust memory on very large sheets.
The first solution that came to my mind is a solution where we write
every string to a file without checking for uniqueness ( I am not sure
if the Excel format actually requires the strings in the shared strings
file to be unique or not)
That would create a large file but the subsequent compressing would
probably take care of that. There may be problems when Excel loads the
file. Perhaps it runs out of memory but perhaps not. That would have to
be tried.

The next thing I explored was doing string interning on disk.
I tried three methods:
1) By trie (An unoptimized radix tree)
2) By B-Tree
3) By a disk hash map

I benchmarked these 3 and it turned out that the hash gave the best
performance (I will share the code with anyone interested upon request)
Normally B-Trees are very good but since the strings do not have a fixed
length we need an extra indirection to a string table and that ruins the
performance (Minimizing the number of seeks is crucial for the performance).

Implementation based on HashMap:
For a test I took the original code of java.util.HashMap and created
from that a class called DiskHashMap.
That class uses an implementation of "RandomAccessStorage" to store the
data in the hash map.
I create two implementations of RandomAccessStorage, namely
ByteArrayRandomAccessStorage and FileRandomAccessStorage.
The first uses the heap in form of a growing byte array and the latter
uses the disk.
Since both implement the same interface we could use the much faster
byte array bases storage until a certain threshold is reached and then
switch to the file based storage and continue from there.
The threshold can be specified in a very accurate was (e.g. 10 MB) since
at all time we know exactly how many bytes the byte array occupies and
we don't rely on unpredictable JVM heap space numbers.

You say that you experimented with "MapDB" but I have personally never
used it so I can't say if it is applicable for this problem. The disk
hash map I have made has no memory usage worth mentioning and should be
quite solid since it is dead simple.
Shooting from the hip, I would say that a "whole database" might by a
bit of an overkill for such a small problem and it also has the risk
that you cannot be sure that the main issue (very low memory footprint) 
has been properly addressed.
I don't know yet how much code in SXSSF needs to be changed to get the
maximum benefit from this. Naively I would say that we keep regular Java
strings in the rows of SXSSFs sliding window and when we flush
then we use the disk hash map, string interner to compute the string
table index which we then write to the file. Then, when the document is
complete, we create an XML representation of the disk hash map file.
Looking at the current code I see that things are different (Apparently
there is a CTRst instance for every interned string) but I don't know
the existing code well enough (didn't make that patch in SXSSF) to know
if there are lots of issues that I have not considered in my naive approach.

At this point we really need Nick, Yegor or someone else to give his advice.

Kind regards,
Alex



--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Using-MapDB-to-reduce-memory-footprint-of-shared-strings-table-in-SXSSF-tp5717375p5717378.html
Sent from the POI - Dev mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
For additional commands, e-mail: dev-help@poi.apache.org


Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Sumedh <su...@gmail.com>.
We'll send you what we have done, it's showing good trade-off performance
(use memory if available, else use disk).

On Tue, Dec 16, 2014 at 3:01 PM, Nick Burch <ap...@gagravarr.org> wrote:
>
> On Tue, 16 Dec 2014, Sumedh wrote:
>
>> 1. For a quick win, is it possible to provide a hook so that we can plug
>> in an overridden implementation of SharedStringTable class? As far as I
>> saw, there is no clean pluggability available right now (but I have very
>> little understanding of POI codebase).
>>
>
> We'd need to tweak things to allow that. However, is working at the CTRst
> level going to be good for you with MapDB or similar? Will serialising then
> deserialising those cause you lots of problems / overhead? Would there be a
> better "thing" to pass back and forth between XSSF / SXSSF / SAX code for a
> shared string?
>
> (There has been discussion lately about trying to avoid the amount of
> xmlbeans objects on public interfaces, so that a switch to something like
> jaxp could be done later if we want to, so this is one case when we can
> consider it)
>
>  2. If that works well, we can explore using MapDB as one of the options
>> to be used natively after considering all the other factors (like licensing
>> and size)...or may be some other smaller library focused only on this
>> aspect, or Alex's homegrown code. :)
>>
>> BTW, MapDB is free as speech and free as beer under Apache License 2.0
>> <https://github.com/jankotek/MapDB/blob/master/doc/license.txt>. :)
>> - https://github.com/jankotek/MapDB/blob/master/license.txt
>>
>
> And small too, so I don't see any major issues with making it an option
> for people wanting lower memory but higher IO reading, assuming we can't
> find a better one (eg from Alex or Lucene!)
>
>
> Nick
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
> For additional commands, e-mail: dev-help@poi.apache.org
>
>

-- 
Cheers,
Sumedh
http://www.linkedin.com/in/sumedhinamdar
Ph: +91 - 95610 99125

Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Sumedh <su...@gmail.com>.
Hi,

Anyone has time to review the patch submitted in
https://issues.apache.org/bugzilla/show_bug.cgi?id=57401 ?

On Tue, Dec 30, 2014 at 2:57 PM, Sumedh <su...@gmail.com> wrote:

> Hi guys,
>
> We've submitted a patch to have an option to use MapDB based shared string
> table instead of fully in-memory one.
> https://issues.apache.org/bugzilla/show_bug.cgi?id=57401
>
> There will be a new constructor to use this approach...
>
> public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize,
> boolean compressTmpFiles, *SharedStringsTableType sharedStringsTableType*)
>
> In our tests, it's performing pretty well in terms of memory footprint...
>
> Please take a look and provide feedback...
>
>
>
>
> On Tue, Dec 16, 2014 at 3:01 PM, Nick Burch <ap...@gagravarr.org> wrote:
>
>> On Tue, 16 Dec 2014, Sumedh wrote:
>>
>>> 1. For a quick win, is it possible to provide a hook so that we can plug
>>> in an overridden implementation of SharedStringTable class? As far as I
>>> saw, there is no clean pluggability available right now (but I have very
>>> little understanding of POI codebase).
>>>
>>
>> We'd need to tweak things to allow that. However, is working at the CTRst
>> level going to be good for you with MapDB or similar? Will serialising then
>> deserialising those cause you lots of problems / overhead? Would there be a
>> better "thing" to pass back and forth between XSSF / SXSSF / SAX code for a
>> shared string?
>>
>> (There has been discussion lately about trying to avoid the amount of
>> xmlbeans objects on public interfaces, so that a switch to something like
>> jaxp could be done later if we want to, so this is one case when we can
>> consider it)
>>
>>  2. If that works well, we can explore using MapDB as one of the options
>>> to be used natively after considering all the other factors (like licensing
>>> and size)...or may be some other smaller library focused only on this
>>> aspect, or Alex's homegrown code. :)
>>>
>>> BTW, MapDB is free as speech and free as beer under Apache License 2.0
>>> <https://github.com/jankotek/MapDB/blob/master/doc/license.txt>. :)
>>> - https://github.com/jankotek/MapDB/blob/master/license.txt
>>>
>>
>> And small too, so I don't see any major issues with making it an option
>> for people wanting lower memory but higher IO reading, assuming we can't
>> find a better one (eg from Alex or Lucene!)
>>
>>
>> Nick
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
>> For additional commands, e-mail: dev-help@poi.apache.org
>>
>>
>
>
> --
> Cheers,
> Sumedh
> http://www.linkedin.com/in/sumedhinamdar
> Ph: +91 - 95610 99125
>



-- 
Cheers,
Sumedh
http://www.linkedin.com/in/sumedhinamdar
Ph: +91 - 95610 99125

Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Sumedh <su...@gmail.com>.
Hi guys,

We've submitted a patch to have an option to use MapDB based shared string
table instead of fully in-memory one.
https://issues.apache.org/bugzilla/show_bug.cgi?id=57401

There will be a new constructor to use this approach...

public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize,
boolean compressTmpFiles, *SharedStringsTableType sharedStringsTableType*)

In our tests, it's performing pretty well in terms of memory footprint...

Please take a look and provide feedback...




On Tue, Dec 16, 2014 at 3:01 PM, Nick Burch <ap...@gagravarr.org> wrote:

> On Tue, 16 Dec 2014, Sumedh wrote:
>
>> 1. For a quick win, is it possible to provide a hook so that we can plug
>> in an overridden implementation of SharedStringTable class? As far as I
>> saw, there is no clean pluggability available right now (but I have very
>> little understanding of POI codebase).
>>
>
> We'd need to tweak things to allow that. However, is working at the CTRst
> level going to be good for you with MapDB or similar? Will serialising then
> deserialising those cause you lots of problems / overhead? Would there be a
> better "thing" to pass back and forth between XSSF / SXSSF / SAX code for a
> shared string?
>
> (There has been discussion lately about trying to avoid the amount of
> xmlbeans objects on public interfaces, so that a switch to something like
> jaxp could be done later if we want to, so this is one case when we can
> consider it)
>
>  2. If that works well, we can explore using MapDB as one of the options
>> to be used natively after considering all the other factors (like licensing
>> and size)...or may be some other smaller library focused only on this
>> aspect, or Alex's homegrown code. :)
>>
>> BTW, MapDB is free as speech and free as beer under Apache License 2.0
>> <https://github.com/jankotek/MapDB/blob/master/doc/license.txt>. :)
>> - https://github.com/jankotek/MapDB/blob/master/license.txt
>>
>
> And small too, so I don't see any major issues with making it an option
> for people wanting lower memory but higher IO reading, assuming we can't
> find a better one (eg from Alex or Lucene!)
>
>
> Nick
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
> For additional commands, e-mail: dev-help@poi.apache.org
>
>


-- 
Cheers,
Sumedh
http://www.linkedin.com/in/sumedhinamdar
Ph: +91 - 95610 99125

Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Nick Burch <ap...@gagravarr.org>.
On Tue, 16 Dec 2014, Sumedh wrote:
> 1. For a quick win, is it possible to provide a hook so that we can plug 
> in an overridden implementation of SharedStringTable class? As far as I 
> saw, there is no clean pluggability available right now (but I have very 
> little understanding of POI codebase).

We'd need to tweak things to allow that. However, is working at the CTRst 
level going to be good for you with MapDB or similar? Will serialising 
then deserialising those cause you lots of problems / overhead? Would 
there be a better "thing" to pass back and forth between XSSF / SXSSF / 
SAX code for a shared string?

(There has been discussion lately about trying to avoid the amount of 
xmlbeans objects on public interfaces, so that a switch to something like 
jaxp could be done later if we want to, so this is one case when we can 
consider it)

> 2. If that works well, we can explore using MapDB as one of the options 
> to be used natively after considering all the other factors (like 
> licensing and size)...or may be some other smaller library focused only 
> on this aspect, or Alex's homegrown code. :)
>
> BTW, MapDB is free as speech and free as beer under Apache License 2.0
> <https://github.com/jankotek/MapDB/blob/master/doc/license.txt>. :)
> - https://github.com/jankotek/MapDB/blob/master/license.txt

And small too, so I don't see any major issues with making it an option 
for people wanting lower memory but higher IO reading, assuming we can't 
find a better one (eg from Alex or Lucene!)

Nick

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
For additional commands, e-mail: dev-help@poi.apache.org


Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Sumedh <su...@gmail.com>.
Thanks Nick.

1. For a quick win, is it possible to provide a hook so that we can plug in
an overridden implementation of SharedStringTable class? As far as I saw,
there is no clean pluggability available right now (but I have very little
understanding of POI codebase).

2. If that works well, we can explore using MapDB as one of the options to
be used natively after considering all the other factors (like licensing
and size)...or may be some other smaller library focused only on this
aspect, or Alex's homegrown code. :)

BTW, MapDB is free as speech and free as beer under Apache License 2.0
<https://github.com/jankotek/MapDB/blob/master/doc/license.txt>. :)
- https://github.com/jankotek/MapDB/blob/master/license.txt








On Mon, Dec 15, 2014 at 7:22 PM, Nick Burch <ap...@gagravarr.org> wrote:
>
> On Sun, 14 Dec 2014, Sumedh wrote:
>
>> We are using POI SXSSF for writing excel files. We faced heap memory usage
>> issues with large excels containing large amounts of text data.
>>
>> Currently, SXSSF stores the shared strings table completely in memory, and
>> if shared strings table is not used, the xlsx file is not compatible with
>> some clients (like iPad) (
>> https://issues.apache.org/bugzilla/show_bug.cgi?id=53130).
>>
>
> I keep hoping that this issue will trip up someone with a hefty support
> contract with Apple, who'll be able to get the Cupertino lads and lasses to
> go and properly read the OOXML spec, but sadly that hasn't happened yet...
>
>  We tried using MapDB to store shared strings table, which flushes entries
>> to disk if there are a large number of entries. It's working quite well,
>> and successfully writes large files where POI currently throws OOM error.
>>
>
> If we were to add a dependency on an on-disk DB to help with this, it'd
> need to be:
>  * Optional - people with mid-sized files could continue as now
>  * Small - adding on-disk support for SXSSF shouldn't dramatically
>    increase the size of the POI library
>  * Suitably licensed - see
>    http://www.apache.org/legal/resolved.html#category-a for what licenses
>    we can accept dependencies under
>  * Well unit tested
>  * Done by someone else ;-)
>
> Currently, everything I do for $DAYJOB can be done with XSSF+SXSSF for
> writing, and XSSF+SAX stuff for reading, so I have no real work need for
> SXSSF to be better memory wise. I therefore can't spent work time on it,
> but I'm happy to spend some persoanl time looking at patches if other
> community members want to put the work in. I suspect many other POI
> committers are the same - the current code is good enough that we can't
> convince our bosses to let us work on it during the day, but we see the
> value for everyone else to give up an evening or two to review patches to
> make it better for others.
>
> So, if an on-disk backed SXSSF shared strings table is of interest, and
> you can find a suitable smallish + tested + licensed library, go ahead and
> start on adding it as an option! http://poi.apache.org/guidelines.html
> should cover the rest of what we need. Ask on the dev list for advice if
> you have a few ways to go, and need suggestions / advice / etc!
>
> Nick
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
> For additional commands, e-mail: dev-help@poi.apache.org
>
>

-- 
Cheers,
Sumedh
http://www.linkedin.com/in/sumedhinamdar
Ph: +91 - 95610 99125

Re: Using MapDB to reduce memory footprint of shared strings table in SXSSF

Posted by Nick Burch <ap...@gagravarr.org>.
On Sun, 14 Dec 2014, Sumedh wrote:
> We are using POI SXSSF for writing excel files. We faced heap memory usage
> issues with large excels containing large amounts of text data.
>
> Currently, SXSSF stores the shared strings table completely in memory, and
> if shared strings table is not used, the xlsx file is not compatible with
> some clients (like iPad) (
> https://issues.apache.org/bugzilla/show_bug.cgi?id=53130).

I keep hoping that this issue will trip up someone with a hefty support 
contract with Apple, who'll be able to get the Cupertino lads and lasses 
to go and properly read the OOXML spec, but sadly that hasn't happened 
yet...

> We tried using MapDB to store shared strings table, which flushes entries
> to disk if there are a large number of entries. It's working quite well,
> and successfully writes large files where POI currently throws OOM error.

If we were to add a dependency on an on-disk DB to help with this, it'd 
need to be:
  * Optional - people with mid-sized files could continue as now
  * Small - adding on-disk support for SXSSF shouldn't dramatically
    increase the size of the POI library
  * Suitably licensed - see
    http://www.apache.org/legal/resolved.html#category-a for what licenses
    we can accept dependencies under
  * Well unit tested
  * Done by someone else ;-)

Currently, everything I do for $DAYJOB can be done with XSSF+SXSSF for 
writing, and XSSF+SAX stuff for reading, so I have no real work need for 
SXSSF to be better memory wise. I therefore can't spent work time on it, 
but I'm happy to spend some persoanl time looking at patches if other 
community members want to put the work in. I suspect many other POI 
committers are the same - the current code is good enough that we can't 
convince our bosses to let us work on it during the day, but we see the 
value for everyone else to give up an evening or two to review patches to 
make it better for others.

So, if an on-disk backed SXSSF shared strings table is of interest, and 
you can find a suitable smallish + tested + licensed library, go ahead and 
start on adding it as an option! http://poi.apache.org/guidelines.html 
should cover the rest of what we need. Ask on the dev list for advice if 
you have a few ways to go, and need suggestions / advice / etc!

Nick

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
For additional commands, e-mail: dev-help@poi.apache.org