[
  {
    "Id": "240226",
    "ThreadId": "70516",
    "Html": "<p>Hi,</p>\r\n<p>I'm trying to zip the output of DataSet.WriteXml via a stream to a zipfile (and of course re-populate a DataSet from a zipped file using DataSet.ReadXml).</p>\r\n<p>The following code creates a zip archive with one entry; however, that entry has zero length. &nbsp;Any ideas on what I'm doing wrong?</p>\r\n<p>&nbsp;</p>\r\n<div style=\"color:Black;background-color:White\">\r\n<pre>DataSet1 ds = <span style=\"color:Blue\">new</span> DataSet1();\r\nds.Pricing.AddPricingRow(<span style=\"color:Blue\">new</span> DateTime(2009, 1, 1), <span style=\"color:#A31515\">&quot;IBM&quot;</span>, 100);\r\nds.Pricing.AddPricingRow(<span style=\"color:Blue\">new</span> DateTime(2009, 1, 2), <span style=\"color:#A31515\">&quot;IBM&quot;</span>, 101);\r\nds.Pricing.AddPricingRow(<span style=\"color:Blue\">new</span> DateTime(2009, 1, 3), <span style=\"color:#A31515\">&quot;IBM&quot;</span>, 102);\r\n\r\nds.WriteXml(<span style=\"color:#A31515\">@&quot;c:\\temp\\test.xml&quot;</span>); <span style=\"color:Green\">//this works fine</span>\r\n\r\nIonic.Zip.ZipFile zip = <span style=\"color:Blue\">new</span> Ionic.Zip.ZipFile();\r\nMemoryStream ms = <span style=\"color:Blue\">new</span> MemoryStream();\r\nIonic.Zip.ZipEntry entry = zip.AddEntry(<span style=\"color:#A31515\">&quot;test.xml&quot;</span>, <span style=\"color:#A31515\">&quot;&quot;</span>, ms);\r\n\r\nds.WriteXml(ms);\r\n\r\nzip.Save(<span style=\"color:#A31515\">@&quot;c:\\temp\\test.xml.zip&quot;</span>);\r\nzip.Dispose();\r\n</pre>\r\n</div>\r\n<p>Any pointers greatly appreciated. &nbsp;Thank you. &nbsp;WLM</p>\r\n<p>&nbsp;</p>",
    "PostedDate": "2009-09-29T18:32:25.42-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "240247",
    "ThreadId": "70516",
    "Html": "<p>Maybe try ms.Seek(0,SeekOrigin.Begin)&nbsp; before calling zip.Save().</p>\r\n<p>I think you've written to the MemoryStream, but the pointer in the MemoryStream is at the end of the stream, at the time you call zip.Save().&nbsp; You want it at the beginning.</p>",
    "PostedDate": "2009-09-29T20:57:38.137-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "240324",
    "ThreadId": "70516",
    "Html": "<p>Beautiful! &nbsp;Worked like a charm. &nbsp;Thanks.</p>",
    "PostedDate": "2009-09-30T02:54:14.44-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "240508",
    "ThreadId": "70516",
    "Html": "<p>Whoops--I spoke too soon.</p>\r\n<p>Setting the stream position to zero&nbsp;did indeed fix the problem in my simple example above; however, in the &quot;real world&quot;, I need to persist very large datasets.&nbsp; When using the MemoryStream technique above I got an OutOfMemoryException.&nbsp; Looks like I need to write directly to the zip file.&nbsp; Is there a way to accomplish this using streams?&nbsp; I realize I could just call the standard DataSet.WriteXml method, zip the resulting file to an archive, and then delete the original file, but&nbsp;I would prefer to do it in&nbsp;one fell swoop without that workaround.&nbsp; Any thoughts on how to accomplish this are appreciated.</p>\r\n<p>Many thanks,<br>WLM</p>",
    "PostedDate": "2009-09-30T09:40:46.13-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "240543",
    "ThreadId": "70516",
    "Html": "<table border=0 width=800>\r\n<tbody>\r\n<tr>\r\n<td>\r\n<p>When ZipFile.Save() is called, all entries are written out to the output.&nbsp; For any entries added as streams with ZipFile.AddEntry(), zipFile.Save calls Read() on those streams.&nbsp; In other words, ZipFile requires a stream that can be&nbsp;read.&nbsp; &nbsp; On the other hand, DataSet can put its data only on a stream that accepts Write().&nbsp; DataSet requires a stream that can be written.</p>\r\n<p>What you need is two threads and an adapter stream -&nbsp;Something like <a href=\"http://msdn.microsoft.com/en-us/magazine/cc163290.aspx\">the BlockingStream Stephen Taub provided in MSDN Magazine</a> .&nbsp; Except I think his class implementation allocates an unlimited number of buffers, which may get you into the out-of-memory condition again.&nbsp; What you want is a BlockingStream with a finite set of buffers.&nbsp;</p>\r\n<p>I previously had a need for something like that so I wrote one. Enclosed below. To use it:</p>\r\n<p>&nbsp;</p>\r\n</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<div style=\"color:Black;background-color:White\">\r\n<pre><span style=\"color:Green\">// thread #1</span>\r\nAdapterStream <span style=\"color:Blue\">as</span> = <span style=\"color:Blue\">new</span> AdapterStream(8192);  <span style=\"color:Green\">// 8k buffer</span>\r\ndataset.WriteXml(<span style=\"color:Blue\">as</span>); \r\n<span style=\"color:Blue\">as</span>.BlockSync(); <span style=\"color:Green\">// returns when ZipFile.Save() completes</span>\r\n\r\n<span style=\"color:Green\">// thread #2</span>\r\n<span style=\"color:Blue\">using</span> (<span style=\"color:Blue\">var</span> zip = <span style=\"color:Blue\">new</span> ZipFile())\r\n{\r\n  zip.AddEntry(<span style=\"color:#A31515\">&quot;mydata.xml&quot;</span>, <span style=\"color:#A31515\">&quot;&quot;</span>, <span style=\"color:Blue\">as</span>); \r\n  zip.Save(whatever);\r\n}\r\n\r\n</pre>\r\n</div>\r\n<p>&nbsp;</p>\r\n<p>AdapterStream looks like this:</p>\r\n<div style=\"color:Black;background-color:White\">\r\n<pre><span style=\"color:Blue\">using</span> System;\r\n<span style=\"color:Blue\">using</span> System.Collections.Generic;\r\n<span style=\"color:Blue\">using</span> System.IO;\r\n<span style=\"color:Blue\">using</span> System.Threading;\r\n\r\n<span style=\"color:Blue\">namespace</span> Cheeso.IO\r\n{\r\n    <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span>\r\n    <span style=\"color:Gray\">///</span><span style=\"color:Green\"> A Stream for passing data between a producer thread and a consumer thread.</span>\r\n    <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/summary&gt;</span>\r\n    <span style=\"color:Gray\">///</span>\r\n    <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;remarks&gt;</span>\r\n    <span style=\"color:Gray\">///</span><span style=\"color:Green\">   Probably want this to use at least 2 blocks, each with a</span>\r\n    <span style=\"color:Gray\">///</span><span style=\"color:Green\">   separate lock, to allow more concurrency.</span>\r\n    <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/remarks&gt;</span>\r\n    <span style=\"color:Blue\">internal</span> <span style=\"color:Blue\">class</span> AdapterStream : Stream\r\n    {\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Used as a monitor to protect state accessible to callers of Read.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">private</span> <span style=\"color:Blue\">object</span> _lockForAll;\r\n        \r\n        <span style=\"color:Blue\">private</span> <span style=\"color:Blue\">byte</span>[] _circularBuffer;\r\n        <span style=\"color:Blue\">private</span> <span style=\"color:Blue\">int</span> _posnWrite;\r\n        <span style=\"color:Blue\">private</span> <span style=\"color:Blue\">int</span> _posnRead;\r\n        <span style=\"color:Blue\">private</span> <span style=\"color:Blue\">int</span> _bytesAvailable;\r\n\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\">   Event used to signal when no more data will be written to the stream.</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">private</span> ManualResetEvent _blockSync;\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\">   Event used to signal when the circular buffer has space</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\">   available for writing.</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">private</span> ManualResetEvent _spaceAvailable;\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\">   Event used to signal that data is available for reading.</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">private</span> ManualResetEvent _dataAvailable;\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Array of events waited on by readers.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">private</span> WaitHandle[] _readEvents;\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">The index into _waitHandles for the _blockSync event.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">private</span> <span style=\"color:Blue\">int</span> _blockSyncIndex;\r\n\r\n\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Initializes the blocking stream.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">public</span> AdapterStream(<span style=\"color:Blue\">int</span> size)\r\n        {\r\n            _circularBuffer= <span style=\"color:Blue\">new</span> <span style=\"color:Blue\">byte</span>[size];\r\n            _blockSync = <span style=\"color:Blue\">new</span> ManualResetEvent(<span style=\"color:Blue\">false</span>);\r\n            _dataAvailable = <span style=\"color:Blue\">new</span> ManualResetEvent(<span style=\"color:Blue\">false</span>);\r\n            _spaceAvailable = <span style=\"color:Blue\">new</span> ManualResetEvent(<span style=\"color:Blue\">true</span>);\r\n            _readEvents = <span style=\"color:Blue\">new</span> WaitHandle[] { _dataAvailable, _blockSync };\r\n            _blockSyncIndex= 1;\r\n            <span style=\"color:Green\">//_lockForRead = new object();</span>\r\n            _lockForAll = <span style=\"color:Blue\">new</span> <span style=\"color:Blue\">object</span>();\r\n        }\r\n\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Determines whether data can be read from the stream.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">bool</span> CanRead { <span style=\"color:Blue\">get</span> { <span style=\"color:Blue\">return</span> <span style=\"color:Blue\">true</span>; } }\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Determines whether the stream can be seeked.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">bool</span> CanSeek { <span style=\"color:Blue\">get</span> { <span style=\"color:Blue\">return</span> <span style=\"color:Blue\">false</span>; } }\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Determines whether data can be written to the stream.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">bool</span> CanWrite { <span style=\"color:Blue\">get</span> { <span style=\"color:Blue\">return</span> <span style=\"color:Blue\">true</span>; } }\r\n\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Flush is a no-op.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">void</span> Flush() { }\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Not supported.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">long</span> Length { <span style=\"color:Blue\">get</span> { <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> NotSupportedException(); } }\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Not supported.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">long</span> Position\r\n        {\r\n            <span style=\"color:Blue\">get</span> { <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> NotSupportedException(); }\r\n            <span style=\"color:Blue\">set</span> { <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> NotSupportedException(); }\r\n        }\r\n\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Not supported.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">long</span> Seek(<span style=\"color:Blue\">long</span> offset, SeekOrigin origin)\r\n        { <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> NotSupportedException(); }\r\n\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Not supported.&lt;/summary&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">void</span> SetLength(<span style=\"color:Blue\">long</span> value) { <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> NotSupportedException(); }\r\n\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> Reads a sequence of bytes from the stream.  Read will block</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> until at least one byte is available for reading or until</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> the stream has been ended for writing.</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/summary&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;param name=&quot;buffer&quot;&gt;</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> An array of bytes. When Read returns, the buffer contains the specified</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> byte array with the values between offset and (offset + count - 1) replaced</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> by the bytes read from the current source.</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/param&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;param name=&quot;offset&quot;&gt;</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> The zero-based byte offset in buffer at which to begin storing the data read</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> from the current stream.</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/param&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;param name=&quot;count&quot;&gt;</span><span style=\"color:Green\">The maximum number of bytes to be read from the current stream.&lt;/param&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;returns&gt;</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> The total number of bytes read into the buffer. This can be less than the</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> number of bytes requested if that many bytes are not currently available,</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> or zero if the end of the stream has been reached.</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/returns&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;remarks&gt;</span><span style=\"color:Green\">This method is thread-safe.&lt;/remarks&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">int</span> Read(<span style=\"color:Blue\">byte</span>[] buffer, <span style=\"color:Blue\">int</span> offset, <span style=\"color:Blue\">int</span> count)\r\n        {\r\n            <span style=\"color:Green\">// Validate all arguments and instance state</span>\r\n            <span style=\"color:Blue\">if</span> (buffer == <span style=\"color:Blue\">null</span>) <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> ArgumentNullException(<span style=\"color:#A31515\">&quot;buffer&quot;</span>);\r\n            <span style=\"color:Blue\">if</span> (offset &lt; 0 || offset &gt;= buffer.Length) <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> ArgumentOutOfRangeException(<span style=\"color:#A31515\">&quot;offset&quot;</span>);\r\n            <span style=\"color:Blue\">if</span> (count &lt; 0 || offset + count &gt; buffer.Length) <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> ArgumentOutOfRangeException(<span style=\"color:#A31515\">&quot;count&quot;</span>);\r\n            <span style=\"color:Blue\">if</span> (_dataAvailable == <span style=\"color:Blue\">null</span>) <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> ObjectDisposedException(GetType().Name);\r\n\r\n            <span style=\"color:Green\">// If no data has been requested, we don't need to do anything</span>\r\n            <span style=\"color:Blue\">if</span> (count == 0) <span style=\"color:Blue\">return</span> 0;\r\n            \r\n            <span style=\"color:Green\">// Loop until we get data or until writing has completed</span>\r\n            <span style=\"color:Blue\">while</span> (<span style=\"color:Blue\">true</span>)\r\n            {\r\n                <span style=\"color:Green\">// Wait for either data to be available or for the sequence to be</span>\r\n                <span style=\"color:Green\">// completed.</span>\r\n                <span style=\"color:Blue\">int</span> handleIndex = WaitHandle.WaitAny(_readEvents);\r\n                \r\n                <span style=\"color:Blue\">lock</span> (_lockForAll)\r\n                {\r\n                    <span style=\"color:Green\">// If nothing is available, loop around to wait again.</span>\r\n                    <span style=\"color:Green\">// This is the blocking part. </span>\r\n                    <span style=\"color:Blue\">if</span> (_bytesAvailable==0)\r\n                    {\r\n                        <span style=\"color:Blue\">if</span> (handleIndex == _blockSyncIndex)\r\n                        {\r\n                            <span style=\"color:Green\">// All done with this item in the sequence,</span>\r\n                            <span style=\"color:Green\">// nothing more to read.</span>\r\n\r\n                            <span style=\"color:Green\">// Signal that the writer can begin writing again (new sequence).</span>\r\n                            _spaceAvailable.Set();\r\n\r\n                            <span style=\"color:Green\">// Turn off the sequence break. It's been handled. </span>\r\n                            _blockSync.Reset();\r\n                            <span style=\"color:Blue\">return</span> 0; <span style=\"color:Green\">// EOF</span>\r\n                        }\r\n\r\n                        <span style=\"color:Green\">// In this case, there's no data available to Read, but the</span>\r\n                        <span style=\"color:Green\">// writer hasn't completed the writes on this sequence. So</span>\r\n                        <span style=\"color:Green\">// loop around, block, and try to read again. This should</span>\r\n                        <span style=\"color:Green\">// never happen, because _bytesAvailable should be nonzero</span>\r\n                        <span style=\"color:Green\">// if _dataAvailable is signalled.  No harm though.</span>\r\n                        <span style=\"color:Blue\">continue</span>;\r\n                    }\r\n                    \r\n                    <span style=\"color:Green\">// Read as many bytes as possible</span>\r\n                    <span style=\"color:Blue\">int</span> bytesToRead= (_bytesAvailable &gt; count) ? count : _bytesAvailable;\r\n                    \r\n                    <span style=\"color:Green\">// Will we need to wrap around in the circ buffer to satisfy the read?</span>\r\n                    <span style=\"color:Blue\">if</span> (_posnRead + bytesToRead &gt; _circularBuffer.Length)\r\n                    {\r\n                        <span style=\"color:Green\">// yes - need to wrap around </span>\r\n                        <span style=\"color:Blue\">int</span> thisBatch = _circularBuffer.Length - _posnRead;\r\n                        Buffer.BlockCopy(_circularBuffer, _posnRead, buffer, offset, thisBatch);\r\n                        _posnRead = 0;\r\n                        offset += thisBatch; <span style=\"color:Green\">// matters only if we loop until the read is done.</span>\r\n                        thisBatch = bytesToRead - thisBatch;\r\n                        Buffer.BlockCopy(_circularBuffer, _posnRead, buffer, offset, thisBatch);\r\n                        _posnRead += thisBatch;\r\n                    }\r\n                    <span style=\"color:Blue\">else</span>\r\n                    {\r\n                        <span style=\"color:Green\">// Satisfy the read without wrap.</span>\r\n                        Buffer.BlockCopy(_circularBuffer, _posnRead, buffer, offset, bytesToRead);\r\n                        _posnRead += bytesToRead;\r\n                    }\r\n                    \r\n                    _bytesAvailable -= bytesToRead;\r\n                    <span style=\"color:Blue\">if</span> (_bytesAvailable == 0) _dataAvailable.Reset();\r\n                    \r\n                    _spaceAvailable.Set();\r\n                    \r\n                    <span style=\"color:Blue\">return</span> bytesToRead;\r\n                }\r\n            }\r\n        }\r\n        \r\n\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Writes a sequence of bytes to the stream.&lt;/summary&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;param name=&quot;buffer&quot;&gt;</span><span style=\"color:Green\">An array of bytes. Write copies count bytes from buffer to the stream.&lt;/param&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;param name=&quot;offset&quot;&gt;</span><span style=\"color:Green\">The zero-based byte offset in buffer at which to begin copying bytes to the stream.&lt;/param&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;param name=&quot;count&quot;&gt;</span><span style=\"color:Green\">The number of bytes to be written to the current stream.&lt;/param&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;remarks&gt;</span><span style=\"color:Green\">This method is thread-safe, and will block until the write can be completed.&lt;/remarks&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">void</span> Write(<span style=\"color:Blue\">byte</span>[] buffer, <span style=\"color:Blue\">int</span> offset, <span style=\"color:Blue\">int</span> count)\r\n        {\r\n            <span style=\"color:Green\">// Validate all arguments and instance state</span>\r\n            <span style=\"color:Blue\">if</span> (buffer == <span style=\"color:Blue\">null</span>) <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> ArgumentNullException(<span style=\"color:#A31515\">&quot;buffer&quot;</span>);\r\n            <span style=\"color:Blue\">if</span> (offset &lt; 0 || offset &gt;= buffer.Length) <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> ArgumentOutOfRangeException(<span style=\"color:#A31515\">&quot;offset&quot;</span>);\r\n            <span style=\"color:Blue\">if</span> (count &lt; 0 || offset + count &gt; buffer.Length) <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> ArgumentOutOfRangeException(<span style=\"color:#A31515\">&quot;count&quot;</span>);\r\n            <span style=\"color:Blue\">if</span> (_dataAvailable == <span style=\"color:Blue\">null</span>) <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> ObjectDisposedException(GetType().Name);\r\n\r\n            <span style=\"color:Green\">// If no data is being written, nothing to do.</span>\r\n            <span style=\"color:Blue\">if</span> (count == 0) <span style=\"color:Blue\">return</span>;\r\n\r\n            <span style=\"color:Blue\">while</span> (count &gt; 0)\r\n            {\r\n                <span style=\"color:Green\">// Wait for space to become available.</span>\r\n                _spaceAvailable.WaitOne();\r\n                \r\n                <span style=\"color:Green\">// Copy the written data into the circularBuffer.</span>\r\n                <span style=\"color:Green\">// Make sure to signal to any readers that data is available.</span>\r\n                <span style=\"color:Blue\">lock</span> (_lockForAll)\r\n                {\r\n                    <span style=\"color:Blue\">int</span> bufferSpaceAvailable = (_posnRead &lt;= _posnWrite)\r\n                        ? _circularBuffer.Length - _posnWrite\r\n                        : _posnRead - _posnWrite - 1;\r\n\r\n                    <span style=\"color:Blue\">int</span> bytesToWrite = (count &lt; bufferSpaceAvailable) ? count : bufferSpaceAvailable;\r\n                    \r\n                    Buffer.BlockCopy(buffer, offset, _circularBuffer, _posnWrite, bytesToWrite);\r\n                    count -= bytesToWrite;\r\n                    offset += bytesToWrite; \r\n                    _bytesAvailable += bytesToWrite;\r\n                    _posnWrite += bytesToWrite;\r\n                    <span style=\"color:Blue\">if</span> (_posnWrite &gt;= _circularBuffer.Length)\r\n                        _posnWrite = 0;\r\n                    _dataAvailable.Set();\r\n\r\n                    <span style=\"color:Blue\">if</span> (_posnWrite==_posnRead)\r\n                        _spaceAvailable.Reset();\r\n                }\r\n            }\r\n        }\r\n\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> Called by the writer to signal to the reader that a block of</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> data is complete.</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/summary&gt;</span>\r\n        <span style=\"color:Gray\">///</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;remarks&gt;</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> This should be called by the writer. This method is thread-safe. Subsequent</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> calls to Write will block until the reader completes all reads of the</span>\r\n        <span style=\"color:Gray\">///</span><span style=\"color:Green\"> just-completed block.</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;/remarks&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">void</span> BlockSync()\r\n        {\r\n            <span style=\"color:Blue\">if</span> (_dataAvailable == <span style=\"color:Blue\">null</span>) <span style=\"color:Blue\">throw</span> <span style=\"color:Blue\">new</span> ObjectDisposedException(GetType().Name);\r\n            <span style=\"color:Blue\">lock</span> (_lockForAll)\r\n            {\r\n                <span style=\"color:Green\">// This will signal the reader that there's a break.</span>\r\n                _blockSync.Set();\r\n\r\n                <span style=\"color:Green\">// This will block the writer til the reader reaches EOF.</span>\r\n                <span style=\"color:Green\">// We don't want the writing filling the buffer again, until</span>\r\n                <span style=\"color:Green\">// the reader has finished reading this block.</span>\r\n                _spaceAvailable.Reset();\r\n            }\r\n        }\r\n\r\n\r\n        \r\n        <span style=\"color:Blue\">private</span> <span style=\"color:Blue\">void</span> FreeEvent(<span style=\"color:Blue\">ref</span> ManualResetEvent e)\r\n        {\r\n            <span style=\"color:Blue\">if</span> (e != <span style=\"color:Blue\">null</span>)\r\n            {\r\n                e.Close();\r\n                e = <span style=\"color:Blue\">null</span>;\r\n            }\r\n        }\r\n\r\n\r\n        \r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;summary&gt;</span><span style=\"color:Green\">Closes the stream and releases all resources associated with it.&lt;/summary&gt;</span>\r\n        <span style=\"color:Gray\">///</span> <span style=\"color:Gray\">&lt;remarks&gt;</span><span style=\"color:Green\">This method is not thread-safe.&lt;/remarks&gt;</span>\r\n        <span style=\"color:Blue\">public</span> <span style=\"color:Blue\">override</span> <span style=\"color:Blue\">void</span> Close()\r\n        {\r\n            <span style=\"color:Blue\">base</span>.Close();\r\n            \r\n            <span style=\"color:Green\">// Free the events</span>\r\n            FreeEvent(<span style=\"color:Blue\">ref</span> _dataAvailable);\r\n            FreeEvent(<span style=\"color:Blue\">ref</span> _spaceAvailable);\r\n            FreeEvent(<span style=\"color:Blue\">ref</span> _blockSync);\r\n        }\r\n    }\r\n}\r\n\r\n</pre>\r\n</div>\r\n<p>&nbsp;</p>\r\n<p>&nbsp;</p>",
    "PostedDate": "2009-09-30T10:31:13.347-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "240690",
    "ThreadId": "70516",
    "Html": "<p>Hi Cheeso,</p>\r\n<p>Thanks for the reply and code. &nbsp;I understand what you are saying from a high level, but the ability to create something like your AdapterStream is beyond my meager skills. &nbsp;Unfortunately the AdapterStream class as written does not compile. &nbsp;In the read method, the bytesToCopy variable in &quot;<span style=\"font-family:Consolas, 'Courier New', Courier, monospace;white-space:pre\"><span style=\"color:blue\">return</span> bytesToCopy&quot; is not recognized.  Perhaps you meant _bytesAvailable? </span></p>\r\n<p><span style=\"font-family:Consolas, 'Courier New', Courier, monospace;white-space:pre\">I also think some of the methods that are stubbed out with NotSupportedExceptions are being called behind the scenes by the ZipFile class.</span></p>\r\n<p><span style=\"font-family:Consolas, 'Courier New', Courier, monospace;white-space:pre\">I attempted to get this running on different threads but I think there are some other things going on in addition to the fact that I probably didn't implement the treading properly.</span></p>\r\n<p><span style=\"font-family:Consolas, 'Courier New', Courier, monospace;white-space:pre\">Best regards,<br>WLM</span></p>\r\n<p><span style=\"font-family:Consolas, 'Courier New', Courier, monospace;white-space:pre\">&nbsp;</span></p>\r\n<div style=\"color:Black;background-color:White\">\r\n<pre><span style=\"color:Blue\">using</span> System;\r\n<span style=\"color:Blue\">using</span> System.Collections.Generic;\r\n<span style=\"color:Blue\">using</span> System.Linq;\r\n<span style=\"color:Blue\">using</span> System.Text;\r\n<span style=\"color:Blue\">using</span> Ionic.Zip;\r\n<span style=\"color:Blue\">using</span> System.Threading;\r\n\r\n<span style=\"color:Blue\">namespace</span> CompressionTest\r\n{\r\n\t<span style=\"color:Blue\">class</span> DataStore\r\n\t{\r\n\t\t<span style=\"color:Blue\">private</span> DataSet1 m_ds;\r\n\t\t<span style=\"color:Blue\">private</span> AdapterStream m_as;\r\n\r\n\t\t<span style=\"color:Blue\">public</span> <span style=\"color:Blue\">void</span> Write()\r\n\t\t{\r\n\t\t\tm_ds = <span style=\"color:Blue\">new</span> DataSet1();\r\n\t\t\tm_ds.Pricing.AddPricingRow(<span style=\"color:Blue\">new</span> DateTime(2009, 1, 1), <span style=\"color:#A31515\">&quot;IBM&quot;</span>, 100);\r\n\t\t\tm_ds.Pricing.AddPricingRow(<span style=\"color:Blue\">new</span> DateTime(2009, 1, 2), <span style=\"color:#A31515\">&quot;IBM&quot;</span>, 101);\r\n\t\t\tm_ds.Pricing.AddPricingRow(<span style=\"color:Blue\">new</span> DateTime(2009, 1, 3), <span style=\"color:#A31515\">&quot;IBM&quot;</span>, 102);\r\n\r\n\t\t\tm_ds.WriteXml(<span style=\"color:#A31515\">@&quot;c:\\temp\\test.xml&quot;</span>); <span style=\"color:Green\">//this works fine</span>\r\n\r\n\t\t\tThread t = <span style=\"color:Blue\">new</span> Thread(<span style=\"color:Blue\">new</span> ThreadStart(Thread1));\r\n\t\t\tt.Start();\r\n\r\n\t\t\tt = <span style=\"color:Blue\">new</span> Thread(<span style=\"color:Blue\">new</span> ThreadStart(Thread2));\r\n\t\t\tt.Start();\r\n\r\n\t\t}\r\n\r\n\t\t<span style=\"color:Blue\">private</span> <span style=\"color:Blue\">void</span> Thread1()\r\n\t\t{\r\n\t\t\tm_as = <span style=\"color:Blue\">new</span> AdapterStream(8192);  <span style=\"color:Green\">// 8k buffer</span>\r\n\t\t\tm_ds.WriteXml(m_as);\r\n\t\t\tm_as.BlockSync(); <span style=\"color:Green\">// returns when ZipFile.Save() completes</span>\r\n\t\t}\r\n\r\n\t\t<span style=\"color:Blue\">private</span> <span style=\"color:Blue\">void</span> Thread2()\r\n\t\t{\r\n\t\t\t<span style=\"color:Blue\">using</span> (<span style=\"color:Blue\">var</span> zip = <span style=\"color:Blue\">new</span> ZipFile())\r\n\t\t\t{\r\n\t\t\t\tzip.AddEntry(<span style=\"color:#A31515\">&quot;test.xml&quot;</span>, <span style=\"color:#A31515\">&quot;&quot;</span>, m_as);\r\n\t\t\t\tzip.Save(<span style=\"color:#A31515\">@&quot;c:\\temp\\test.xml.zip&quot;</span>);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n</pre>\r\n</div>\r\n&nbsp;\r\n<p>&nbsp;</p>\r\n<p><span style=\"font-family:Consolas, 'Courier New', Courier, monospace;white-space:pre\"><br></span></p>",
    "PostedDate": "2009-09-30T17:14:45.723-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "240740",
    "ThreadId": "70516",
    "Html": "<table border=0 width=800>\r\n<tbody>\r\n<tr>\r\n<td>\r\n<p>Hey Wlm, ah, that code I posted was not quite right. I've fixed it and updated it in the post above.&nbsp; It compiles now :0.&nbsp;&nbsp; Anyway, this is the code I used to verify that the idea works:</p>\r\n</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<div style=\"color:Black;background-color:White\">\r\n<pre><span style=\"color:Blue\">private</span> Cheeso.IO.AdapterStream as1;\r\n<span style=\"color:Blue\">private</span> DataSet ds1;\r\n\r\n<span style=\"color:Blue\">private</span> <span style=\"color:Blue\">void</span> SaveDataset(<span style=\"color:Blue\">object</span> ignored)\r\n{\r\n    System.Console.WriteLine(<span style=\"color:#A31515\">&quot;writing dataset to as1...&quot;</span>);\r\n    ds1.WriteXml(as1); \r\n    as1.BlockSync(); \r\n}\r\n\r\n<span style=\"color:Blue\">public</span> <span style=\"color:Blue\">void</span> Run()\r\n{\r\n    System.Data.SqlClient.SqlConnection c1= <span style=\"color:Blue\">new</span> System.Data.SqlClient.SqlConnection(connstring1);\r\n\r\n    System.Data.SqlClient.SqlDataAdapter da = <span style=\"color:Blue\">new</span> System.Data.SqlClient.SqlDataAdapter();\r\n    da.SelectCommand=  <span style=\"color:Blue\">new</span> System.Data.SqlClient.SqlCommand(strSelect);\r\n    da.SelectCommand.Connection= c1;\r\n\r\n    System.Console.WriteLine(<span style=\"color:#A31515\">&quot;Create dataset...&quot;</span>);\r\n\r\n    ds1 = <span style=\"color:Blue\">new</span> DataSet();\r\n    System.Console.WriteLine(<span style=\"color:#A31515\">&quot;Fill dataset...&quot;</span>);\r\n    da.Fill(ds1, <span style=\"color:#A31515\">&quot;Invoices&quot;</span>);\r\n\r\n    System.Console.WriteLine(<span style=\"color:#A31515\">&quot;Save dataset to xml file...&quot;</span>);\r\n    ds1.WriteXml(xmlOutputFile); <span style=\"color:Green\">//this works fine</span>\r\n\r\n    as1 = <span style=\"color:Blue\">new</span> Cheeso.IO.AdapterStream(8192);\r\n\r\n    ThreadPool.QueueUserWorkItem(<span style=\"color:Blue\">new</span> WaitCallback(SaveDataset), <span style=\"color:Blue\">null</span>);\r\n\r\n    <span style=\"color:Blue\">using</span>(Ionic.Zip.ZipFile zip = <span style=\"color:Blue\">new</span> Ionic.Zip.ZipFile())\r\n    {\r\n        Ionic.Zip.ZipEntry entry = zip.AddEntry(zipEntryName, <span style=\"color:#A31515\">&quot;&quot;</span>, as1);\r\n        zip.Save(zipFileName);\r\n    }\r\n\r\n    <span style=\"color:Green\">// compare datasets</span>\r\n    DataSet ds2 = <span style=\"color:Blue\">new</span> DataSet();\r\n    ds2.ReadXml(xmlOutputFile);\r\n\r\n    DataSet ds3 = <span style=\"color:Blue\">new</span> DataSet();\r\n    <span style=\"color:Blue\">using</span>(Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(zipFileName))\r\n    {\r\n        <span style=\"color:Green\">// load a DataSet directly from a Stream created for the entry in the zip</span>\r\n        <span style=\"color:Blue\">var</span> s = zip[zipEntryName].OpenReader();\r\n        ds3.ReadXml(s);\r\n    }\r\n\r\n    CompareDatasets(ds2, ds3);\r\n}\r\n\r\n</pre>\r\n</div>\r\n<table border=0 width=800>\r\n<tbody>\r\n<tr>\r\n<td>\r\n<p>The DataSet is written to the AdapterStream within SaveDataset(). Each call to AdapterStream.Write() buffers the data.&nbsp; At the same time, the zip.Save() calls Read() on the Stream and gets the data out of the buffer. &nbsp;</p>\r\n</td>\r\n</tr>\r\n</tbody>\r\n</table>",
    "PostedDate": "2009-09-30T22:15:21.56-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "241226",
    "ThreadId": "70516",
    "Html": "<p>Cheeso,</p>\r\n<p>Wow, thanks for taking the time to straightened that out.&nbsp; I did get one NotSupportedException in the Length property of AdapterStream, but haven't been able to replicate it since.&nbsp; That said, I set a breakpoint and the ZipFile class is definitely calling the Length method and handling the exception.&nbsp; I changed it to return _circularBuffer.Length with no ill effects as far as I can tell.&nbsp; Otherwise it works great.&nbsp; Hopefully these postings will help someone else out down the road.&nbsp; Thanks.</p>\r\n<p>WLM</p>",
    "PostedDate": "2009-10-02T02:57:20.797-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "241387",
    "ThreadId": "70516",
    "Html": "<table border=0 width=800>\r\n<tbody>\r\n<tr>\r\n<td>\r\n<p>&gt; return _circularBuffer.Length</p>\r\n<p>That is not the correct value to return for the stream.&nbsp;</p>\r\n<p>For some streams, such as non-seekable (forward-only) read-only streams, the Stream.Length property is only knowable after all bytes have actually been read.&nbsp; The AdapterStream is one such stream type.&nbsp; The DotNetZip library is aware that this occurs for some stream types, which is why it handles the exception thrown.&nbsp;</p>\r\n<p>It isn't necessary, and it is incorrect, for you to change the Length property to return _circularBuffer.Length .</p>\r\n<p>It could result in a broken zip file - in other words a zipentry will not contain all the bytes from your dataset.&nbsp;</p>\r\n<p>good luck.</p>\r\n<p>&nbsp;</p>\r\n</td>\r\n</tr>\r\n</tbody>\r\n</table>",
    "PostedDate": "2009-10-02T09:58:38.053-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "241494",
    "ThreadId": "70516",
    "Html": "<p>Understood.&nbsp; I'll quickly change that back to the way it was.&nbsp;&nbsp;Some of my xml files were 100's of megs.&nbsp; They compress down nicely now, usually by around 95%.&nbsp;</p>",
    "PostedDate": "2009-10-02T13:42:58.293-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "241506",
    "ThreadId": "70516",
    "Html": "<p>XML is <em>very </em>compressible.&nbsp; Particularly DataSet XML.</p>",
    "PostedDate": "2009-10-02T14:08:56.843-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "241827",
    "ThreadId": "70516",
    "Html": "<p>WLM,</p>\r\n<p>followup.&nbsp; I modified DotNetZip to add a new feature to deal with this situation more cleanly.</p>\r\n<p>If you download v1.9.0.12 (available now)&nbsp; you will be able to do something like this to save a dataset into a zip file, without writing a file to the filesystem.</p>\r\n<div style=\"color:Black;background-color:White\">\r\n<pre>DataSet ds1 = <span style=\"color:Blue\">new</span> DataSet();\r\nda.Fill(ds1, <span style=\"color:#A31515\">&quot;Invoices&quot;</span>);\r\n<span style=\"color:Blue\">using</span>(Ionic.Zip.ZipFile zip = <span style=\"color:Blue\">new</span> Ionic.Zip.ZipFile())\r\n{\r\n    zip.AddEntry(zipEntryName, (name,stream) =&gt; ds1.WriteXml(stream) );\r\n    zip.Save(zipFileName);\r\n}\r\n</pre>\r\n</div>\r\n<p>Using that programming model requires .NET 3.5, for the anonymous methods.</p>\r\n<p>I recommend using this new feature over the AdapterStream thing I sent you.</p>",
    "PostedDate": "2009-10-03T23:57:45.693-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "241990",
    "ThreadId": "70516",
    "Html": "<p>Works perfectly. &nbsp;Very nice to have it all contained within DotNetZip, hiding the complexity from neophytes like me.</p>\r\n<p>Thanks Cheeso.</p>\r\n<p>&nbsp;</p>",
    "PostedDate": "2009-10-04T18:55:45.64-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "242047",
    "ThreadId": "70516",
    "Html": "<p>just to clarify, can we close the supplied stream at the end of the write? many xxx.write(stream) methods are closing the stream at the end.</p>",
    "PostedDate": "2009-10-05T00:27:38.133-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "242213",
    "ThreadId": "70516",
    "Html": "<table border=0 width=800>\r\n<tbody>\r\n<tr>\r\n<td>\r\n<p>GM,</p>\r\n<p>what are you asking here?&nbsp; Do you want the application to be responsible for closing the stream?&nbsp; Or do you want DotNetZip to be responsible for closing the stream?&nbsp; Or ... are you simply asking for clarification on the way it works?</p>\r\n<p>The way it works now, is that DotNetZip opens and configures the stream, before providing it to the application when calling the delegate.&nbsp; DotNetZip also takes responsibility for&nbsp;closing the stream, after the delegate returns.&nbsp;</p>\r\n<p>On the other hand, the doc for System.IO.Stream says that</p>\r\n<blockquote style=\"border:thin dotted #800080;padding:1em\">If the stream is already closed, a call to Close throws no exceptions.</blockquote>\r\n<p>Do you have a particular implementation of xxx.Write(stream) that closes the stream, and causes a problem &nbsp;?</p>\r\n<p>&nbsp;</p>\r\n</td>\r\n</tr>\r\n</tbody>\r\n</table>",
    "PostedDate": "2009-10-05T08:36:19.533-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "242534",
    "ThreadId": "70516",
    "Html": "<p>I wanted to know if it is allowed to close the supplied stream, because there are a lot of existing methods in the framework that can be used, and a lot are closing the stream.</p>\r\n<p>my&nbsp;understanding is now:&nbsp;there is no problem.</p>",
    "PostedDate": "2009-10-06T06:34:23.053-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  }
]