1'use strict';
2(function () {
3
4  class RandomPushSource {
5    constructor(toPush) {
6      this.pushed = 0;
7      this.toPush = toPush;
8      this.started = false;
9      this.paused = false;
10      this.closed = false;
11
12      this._intervalHandle = null;
13    }
14
15    readStart() {
16      if (this.closed) {
17        return;
18      }
19
20      if (!this.started) {
21        this._intervalHandle = setInterval(writeChunk, 2);
22        this.started = true;
23      }
24
25      if (this.paused) {
26        this._intervalHandle = setInterval(writeChunk, 2);
27        this.paused = false;
28      }
29
30      const source = this;
31      function writeChunk() {
32        if (source.paused) {
33          return;
34        }
35
36        source.pushed++;
37
38        if (source.toPush > 0 && source.pushed > source.toPush) {
39          if (source._intervalHandle) {
40            clearInterval(source._intervalHandle);
41            source._intervalHandle = undefined;
42          }
43          source.closed = true;
44          source.onend();
45        } else {
46          source.ondata(randomChunk(128));
47        }
48      }
49    }
50
51    readStop() {
52      if (this.paused) {
53        return;
54      }
55
56      if (this.started) {
57        this.paused = true;
58        clearInterval(this._intervalHandle);
59        this._intervalHandle = undefined;
60      } else {
61        throw new Error('Can\'t pause reading an unstarted source.');
62      }
63    }
64  }
65
66  function randomChunk(size) {
67    let chunk = '';
68
69    for (let i = 0; i < size; ++i) {
70      // Add a random character from the basic printable ASCII set.
71      chunk += String.fromCharCode(Math.round(Math.random() * 84) + 32);
72    }
73
74    return chunk;
75  }
76
77  function readableStreamToArray(readable, reader) {
78    if (reader === undefined) {
79      reader = readable.getReader();
80    }
81
82    const chunks = [];
83
84    return pump();
85
86    function pump() {
87      return reader.read().then(result => {
88        if (result.done) {
89          return chunks;
90        }
91
92        chunks.push(result.value);
93        return pump();
94      });
95    }
96  }
97
98  class SequentialPullSource {
99    constructor(limit, options) {
100      const async = options && options.async;
101
102      this.current = 0;
103      this.limit = limit;
104      this.opened = false;
105      this.closed = false;
106
107      this._exec = f => f();
108      if (async) {
109        this._exec = f => step_timeout(f, 0);
110      }
111    }
112
113    open(cb) {
114      this._exec(() => {
115        this.opened = true;
116        cb();
117      });
118    }
119
120    read(cb) {
121      this._exec(() => {
122        if (++this.current <= this.limit) {
123          cb(null, false, this.current);
124        } else {
125          cb(null, true, null);
126        }
127      });
128    }
129
130    close(cb) {
131      this._exec(() => {
132        this.closed = true;
133        cb();
134      });
135    }
136  }
137
138  function sequentialReadableStream(limit, options) {
139    const sequentialSource = new SequentialPullSource(limit, options);
140
141    const stream = new ReadableStream({
142      start() {
143        return new Promise((resolve, reject) => {
144          sequentialSource.open(err => {
145            if (err) {
146              reject(err);
147            }
148            resolve();
149          });
150        });
151      },
152
153      pull(c) {
154        return new Promise((resolve, reject) => {
155          sequentialSource.read((err, done, chunk) => {
156            if (err) {
157              reject(err);
158            } else if (done) {
159              sequentialSource.close(err2 => {
160                if (err2) {
161                  reject(err2);
162                }
163                c.close();
164                resolve();
165              });
166            } else {
167              c.enqueue(chunk);
168              resolve();
169            }
170          });
171        });
172      }
173    });
174
175    stream.source = sequentialSource;
176
177    return stream;
178  }
179
180  function transferArrayBufferView(view) {
181    const noopByteStream = new ReadableStream({
182      type: 'bytes',
183      pull(c) {
184        c.byobRequest.respond(c.byobRequest.view.byteLength);
185        c.close();
186      }
187    });
188    const reader = noopByteStream.getReader({ mode: 'byob' });
189    return reader.read(view).then((result) => result.value);
190  }
191
192  self.RandomPushSource = RandomPushSource;
193  self.readableStreamToArray = readableStreamToArray;
194  self.sequentialReadableStream = sequentialReadableStream;
195  self.transferArrayBufferView = transferArrayBufferView;
196
197}());
198