keramics_compression/
deflate.rs

1/* Copyright 2024-2025 Joachim Metz <joachim.metz@gmail.com>
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may
5 * obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 * License for the specific language governing permissions and limitations
11 * under the License.
12 */
13
14//! DEFLATE decompression.
15//!
16//! Provides decompression support for DEFLATE compressed data (RFC 1951).
17
18use keramics_core::ErrorTrace;
19use keramics_core::mediator::Mediator;
20
21use super::huffman::HuffmanTree;
22use super::traits::Bitstream;
23
24/// Uncompressed DEFLATE block type.
25const DEFLATE_BLOCK_TYPE_UNCOMPRESED: u32 = 0;
26
27/// Fixed Huffmann trees encoded DEFLATE block type.
28const DEFLATE_BLOCK_TYPE_HUFFMAN_FIXED: u32 = 1;
29
30/// Dynamic Huffmann trees encoded DEFLATE block type.
31const DEFLATE_BLOCK_TYPE_HUFFMAN_DYNAMIC: u32 = 2;
32
33/// Sequence of code size indexes for building dynamic Huffman trees.
34const DEFLATE_CODE_SIZES_SEQUENCE: [u8; 19] = [
35    16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
36];
37
38/// Base values of literal codes for decoding Huffman encoded blocks.
39const DEFLATE_LITERAL_CODES_BASE: [u16; 29] = [
40    3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,
41    163, 195, 227, 258,
42];
43
44/// Number of extra bits of literal codes for decoding Huffman encoded blocks.
45const DEFLATE_LITERAL_CODES_NUMBER_OF_EXTRA_BITS: [u16; 29] = [
46    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,
47];
48
49/// Base values of distances codes for decoding Huffman encoded blocks.
50const DEFLATE_DISTANCE_CODES_BASE: [u16; 30] = [
51    1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
52    2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577,
53];
54
55/// Number of extra bits of distance codes for decoding Huffman encoded blocks.
56const DEFLATE_DISTANCE_CODES_NUMBER_OF_EXTRA_BITS: [u16; 30] = [
57    0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13,
58    13,
59];
60
61/// Bitstream for DEFLATE compressed data.
62pub(super) struct DeflateBitstream<'a> {
63    /// Byte steam.
64    data: &'a [u8],
65
66    /// Current offset in the byte stream.
67    pub data_offset: usize,
68
69    /// Size of the byte stream in bytes.
70    pub data_size: usize,
71
72    /// Bits buffer.
73    bits: u32,
74
75    /// Number of bits in the bits buffer.
76    pub number_of_bits: usize,
77}
78
79impl<'a> DeflateBitstream<'a> {
80    /// Creates a new bitstream.
81    pub fn new(data: &'a [u8], data_offset: usize) -> Self {
82        let data_size: usize = data.len();
83        Self {
84            data: data,
85            data_offset: data_offset,
86            data_size: data_size,
87            bits: 0,
88            number_of_bits: 0,
89        }
90    }
91
92    /// Copies bytes from the bitstream.
93    /// Note that this flushes the internal bits buffer.
94    pub fn copy_bytes(
95        &mut self,
96        read_size: usize,
97        output_data: &mut [u8],
98        output_data_offset: usize,
99        output_data_size: usize,
100    ) -> Result<(), ErrorTrace> {
101        let data_end_offset: usize = self.data_offset + read_size;
102        let output_data_end_offset: usize = output_data_offset + read_size;
103
104        if data_end_offset > self.data_size {
105            return Err(keramics_core::error_trace_new!(
106                "Invalid compressed data value too small"
107            ));
108        }
109        if output_data_end_offset > output_data_size {
110            return Err(keramics_core::error_trace_new!(
111                "Invalid uncompressed data value too small"
112            ));
113        }
114        output_data[output_data_offset..output_data_end_offset]
115            .copy_from_slice(&self.data[self.data_offset..data_end_offset]);
116
117        self.data_offset = data_end_offset;
118
119        // Flush the bits buffer.
120        self.bits = 0;
121        self.number_of_bits = 0;
122
123        Ok(())
124    }
125
126    /// Reads input data forwards into the bits buffer in little-endian byte order.
127    #[inline(always)]
128    fn read_data(&mut self, number_of_bits: usize) {
129        while self.number_of_bits < number_of_bits {
130            // If the bit stream overflows fill the bit buffer with 0 byte values.
131            if self.data_offset < self.data_size {
132                self.bits |= (self.data[self.data_offset] as u32) << self.number_of_bits;
133                self.data_offset += 1;
134            }
135            self.number_of_bits += 8;
136        }
137    }
138
139    /// Unread input data from the bits buffer.
140    #[inline(always)]
141    pub(super) fn unread_data(&mut self) {
142        while self.number_of_bits > 8 {
143            self.bits >>= 8;
144            self.number_of_bits -= 8;
145
146            self.data_offset -= 1;
147        }
148    }
149}
150
151impl<'a> Bitstream for DeflateBitstream<'a> {
152    /// Retrieves a bit value.
153    fn get_value(&mut self, number_of_bits: usize) -> u32 {
154        // Note that this does not check if number_of_bits <= 32
155        let mut bit_value: u32 = 0;
156
157        let mut bit_offset: usize = 0;
158        while bit_offset < number_of_bits {
159            let mut read_size: usize = number_of_bits - bit_offset;
160            if read_size > 24 {
161                read_size = 24;
162            }
163            if self.number_of_bits < read_size {
164                self.read_data(read_size);
165            }
166            let mut value_32bit: u32 = self.bits;
167
168            if read_size == 32 {
169                self.bits = 0;
170            } else {
171                value_32bit &= !(0xffffffff << read_size);
172
173                self.bits >>= read_size;
174            }
175            self.number_of_bits -= read_size;
176
177            if bit_offset > 0 {
178                value_32bit <<= bit_offset;
179            }
180            bit_value |= value_32bit;
181            bit_offset += read_size;
182        }
183        bit_value
184    }
185
186    /// Skips a number of bits.
187    fn skip_bits(&mut self, number_of_bits: usize) {
188        // Note that this does not check if number_of_bits <= 32
189        let mut bit_offset: usize = 0;
190        while bit_offset < number_of_bits {
191            let mut read_size: usize = number_of_bits - bit_offset;
192            if read_size > 24 {
193                read_size = 24;
194            }
195            if self.number_of_bits < read_size {
196                self.read_data(read_size);
197            }
198            if read_size == 32 {
199                self.bits = 0;
200            } else {
201                self.bits >>= read_size;
202            }
203            self.number_of_bits -= read_size;
204
205            bit_offset += read_size;
206        }
207    }
208}
209
210/// Block header used by DEFLATE compressed data.
211struct DeflateBlockHeader {
212    /// Block type.
213    pub block_type: u32,
214
215    /// Last block flag.
216    pub last_block_flag: u32,
217}
218
219impl DeflateBlockHeader {
220    /// Creates a new block header.
221    pub fn new() -> Self {
222        Self {
223            block_type: 0,
224            last_block_flag: 0,
225        }
226    }
227
228    /// Reads the block header from a bitstream.
229    pub fn read_from_bitstream(
230        &mut self,
231        bitstream: &mut DeflateBitstream,
232    ) -> Result<(), ErrorTrace> {
233        let value_32bit: u32 = bitstream.get_value(3);
234
235        self.last_block_flag = value_32bit & 0x00000001;
236        self.block_type = value_32bit >> 1;
237
238        let mediator = Mediator::current();
239        if mediator.debug_output {
240            let mut string_parts: Vec<String> = Vec::new();
241            string_parts.push(format!("DeflateBlockHeader {{\n"));
242            string_parts.push(format!("    last_block_flag: {},\n", self.last_block_flag));
243            string_parts.push(format!("    block_type: {},\n", self.block_type));
244            string_parts.push(format!("}}\n\n"));
245
246            mediator.debug_print(string_parts.join(""));
247        }
248        Ok(())
249    }
250}
251
252// TODO: make fixed huffman trees static?
253
254/// Context for decompressing DEFLATE compressed data.
255pub struct DeflateContext {
256    /// Fixed Huffman tree for decoding literals.
257    fixed_literals_huffman_tree: HuffmanTree,
258
259    /// Fixed Huffman tree for decoding distances.
260    fixed_distances_huffman_tree: HuffmanTree,
261
262    /// Value to indicate if the fixed Huffman trees have been build.
263    build_fixed_huffman_trees: bool,
264
265    /// Uncompressed data size.
266    pub uncompressed_data_size: usize,
267}
268
269impl DeflateContext {
270    /// Creates a new context.
271    pub fn new() -> Self {
272        Self {
273            fixed_literals_huffman_tree: HuffmanTree::new(288, 15),
274            fixed_distances_huffman_tree: HuffmanTree::new(30, 15),
275            build_fixed_huffman_trees: false,
276            uncompressed_data_size: 0,
277        }
278    }
279
280    /// Builds dynamic Huffman trees from the compressed data in the bitstream.
281    fn build_dynamic_huffman_trees(
282        &mut self,
283        bitstream: &mut DeflateBitstream,
284        literals_huffman_tree: &mut HuffmanTree,
285        distances_huffman_tree: &mut HuffmanTree,
286    ) -> Result<(), ErrorTrace> {
287        let mut code_sizes: Vec<u8> = vec![0; 316];
288
289        let mut value_32bit: u32 = bitstream.get_value(14);
290
291        let number_of_literal_codes: usize = (value_32bit & 0x0000001f) as usize + 257;
292
293        if number_of_literal_codes > 286 {
294            return Err(keramics_core::error_trace_new!(format!(
295                "Invalid number of literal codes: {} value out of bounds",
296                number_of_literal_codes
297            )));
298        }
299        value_32bit >>= 5;
300
301        let number_of_distance_codes: usize = (value_32bit & 0x0000001f) as usize + 1;
302
303        if number_of_distance_codes > 30 {
304            return Err(keramics_core::error_trace_new!(format!(
305                "Invalid number of distance codes: {} value out of bounds",
306                number_of_distance_codes
307            )));
308        }
309        value_32bit >>= 5;
310
311        let number_of_code_sizes: usize = (value_32bit as usize) + 4;
312
313        let mediator = Mediator::current();
314        if mediator.debug_output {
315            let mut string_parts: Vec<String> = Vec::new();
316            string_parts.push(format!("DeflateContext::build_dynamic_huffman_trees {{\n"));
317            string_parts.push(format!(
318                "    number_of_literal_codes: {},\n",
319                number_of_literal_codes
320            ));
321            string_parts.push(format!(
322                "    number_of_distance_codes: {},\n",
323                number_of_distance_codes
324            ));
325            string_parts.push(format!(
326                "    number_of_code_sizes: {},\n",
327                number_of_code_sizes
328            ));
329            string_parts.push(format!("}}\n\n"));
330
331            mediator.debug_print(string_parts.join(""));
332        }
333        for sequence_index in 0..number_of_code_sizes {
334            let code_size: u32 = bitstream.get_value(3);
335            let code_size_index: usize = DEFLATE_CODE_SIZES_SEQUENCE[sequence_index] as usize;
336
337            code_sizes[code_size_index] = code_size as u8;
338        }
339        for sequence_index in number_of_code_sizes..19 {
340            let code_size_index: usize = DEFLATE_CODE_SIZES_SEQUENCE[sequence_index] as usize;
341
342            code_sizes[code_size_index] = 0;
343        }
344        let mut codes_huffman_tree: HuffmanTree = HuffmanTree::new(19, 15);
345        codes_huffman_tree.build(&code_sizes[0..19])?;
346
347        let number_of_codes: usize = number_of_literal_codes + number_of_distance_codes;
348        let mut code_size_index: usize = 0;
349
350        while code_size_index < number_of_codes {
351            let symbol: u16 = codes_huffman_tree.decode_symbol(bitstream)?;
352
353            if symbol < 16 {
354                code_sizes[code_size_index] = symbol as u8;
355
356                code_size_index += 1;
357
358                continue;
359            }
360            if code_size_index == 0 && symbol == 16 {
361                return Err(keramics_core::error_trace_new!(format!(
362                    "Invalid code size index: {} value out of bounds",
363                    code_size_index
364                )));
365            }
366            if symbol > 18 {
367                return Err(keramics_core::error_trace_new!(format!(
368                    "Invalid symbol: {} value out of bounds",
369                    symbol
370                )));
371            }
372            let code_size: u8 = if symbol == 16 {
373                code_sizes[code_size_index - 1]
374            } else {
375                0
376            };
377            let mut times_to_repeat: u32 = if symbol == 16 {
378                bitstream.get_value(2) + 3
379            } else if symbol == 17 {
380                bitstream.get_value(3) + 3
381            } else {
382                bitstream.get_value(7) + 11
383            };
384            if code_size_index + times_to_repeat as usize > number_of_codes {
385                return Err(keramics_core::error_trace_new!(format!(
386                    "Invalid times to repeat: {} value out of bounds",
387                    times_to_repeat
388                )));
389            }
390            while times_to_repeat > 0 {
391                code_sizes[code_size_index] = code_size;
392
393                code_size_index += 1;
394                times_to_repeat -= 1;
395            }
396        }
397        if code_sizes[256] == 0 {
398            return Err(keramics_core::error_trace_new!(
399                "End-of-block code value missing in literal codes"
400            ));
401        }
402        literals_huffman_tree.build(&code_sizes[0..number_of_literal_codes])?;
403        distances_huffman_tree.build(&code_sizes[number_of_literal_codes..number_of_codes])?;
404
405        Ok(())
406    }
407
408    /// Builds fixed (predefined) Huffman trees.
409    fn build_fixed_huffman_trees(&mut self) -> Result<(), ErrorTrace> {
410        let mut code_sizes: Vec<u8> = vec![0; 318];
411
412        for symbol in 0..318 {
413            if symbol < 144 {
414                code_sizes[symbol] = 8;
415            } else if symbol < 256 {
416                code_sizes[symbol] = 9;
417            } else if symbol < 280 {
418                code_sizes[symbol] = 7;
419            } else if symbol < 288 {
420                code_sizes[symbol] = 8;
421            } else {
422                code_sizes[symbol] = 5;
423            }
424        }
425        self.fixed_literals_huffman_tree
426            .build(&code_sizes[0..288])?;
427        self.fixed_distances_huffman_tree
428            .build(&code_sizes[288..318])?;
429        self.build_fixed_huffman_trees = true;
430
431        Ok(())
432    }
433
434    /// Decompress data.
435    pub fn decompress(
436        &mut self,
437        compressed_data: &[u8],
438        uncompressed_data: &mut [u8],
439    ) -> Result<(), ErrorTrace> {
440        let mut bitstream: DeflateBitstream = DeflateBitstream::new(compressed_data, 0);
441
442        self.decompress_bitstream(&mut bitstream, uncompressed_data)
443    }
444
445    /// Decompress a bitstream.
446    pub(super) fn decompress_bitstream(
447        &mut self,
448        bitstream: &mut DeflateBitstream,
449        uncompressed_data: &mut [u8],
450    ) -> Result<(), ErrorTrace> {
451        let mut uncompressed_data_offset: usize = 0;
452        let uncompressed_data_size: usize = uncompressed_data.len();
453
454        while bitstream.data_offset < bitstream.data_size {
455            let mut block_header: DeflateBlockHeader = DeflateBlockHeader::new();
456            block_header.read_from_bitstream(bitstream)?;
457
458            match block_header.block_type {
459                DEFLATE_BLOCK_TYPE_UNCOMPRESED => {
460                    // Ignore the bits in the buffer upto the next byte.
461                    let skip_bits: usize = bitstream.number_of_bits & 0x07;
462
463                    if skip_bits > 0 {
464                        bitstream.skip_bits(skip_bits);
465                    }
466                    let value_32bit: u32 = bitstream.get_value(32);
467                    let block_size: usize = (value_32bit & 0x0000ffff) as usize;
468                    let block_size_copy: usize = ((value_32bit >> 16) ^ 0xffff) as usize;
469
470                    if block_size != block_size_copy {
471                        return Err(keramics_core::error_trace_new!(format!(
472                            "Mismatch in uncompressed block size: {} and copy: {}",
473                            block_size, block_size_copy
474                        )));
475                    }
476                    if block_size > 0 {
477                        bitstream.copy_bytes(
478                            block_size,
479                            uncompressed_data,
480                            uncompressed_data_offset,
481                            uncompressed_data_size,
482                        )?;
483                        uncompressed_data_offset += block_size;
484                    }
485                }
486                DEFLATE_BLOCK_TYPE_HUFFMAN_FIXED => {
487                    if !self.build_fixed_huffman_trees {
488                        self.build_fixed_huffman_trees()?;
489                    }
490                    self.decompress_huffmann_encoded_block(
491                        bitstream,
492                        &self.fixed_literals_huffman_tree,
493                        &self.fixed_distances_huffman_tree,
494                        uncompressed_data,
495                        &mut uncompressed_data_offset,
496                        uncompressed_data_size,
497                    )?;
498                }
499                DEFLATE_BLOCK_TYPE_HUFFMAN_DYNAMIC => {
500                    let mut dynamic_literals_huffman_tree: HuffmanTree = HuffmanTree::new(288, 15);
501                    let mut dynamic_distances_huffman_tree: HuffmanTree = HuffmanTree::new(30, 15);
502
503                    self.build_dynamic_huffman_trees(
504                        bitstream,
505                        &mut dynamic_literals_huffman_tree,
506                        &mut dynamic_distances_huffman_tree,
507                    )?;
508                    self.decompress_huffmann_encoded_block(
509                        bitstream,
510                        &dynamic_literals_huffman_tree,
511                        &dynamic_distances_huffman_tree,
512                        uncompressed_data,
513                        &mut uncompressed_data_offset,
514                        uncompressed_data_size,
515                    )?;
516                }
517                _ => {
518                    return Err(keramics_core::error_trace_new!("Unsupported block type"));
519                }
520            }
521            if block_header.last_block_flag != 0 {
522                break;
523            }
524        }
525        self.uncompressed_data_size = uncompressed_data_offset;
526
527        Ok(())
528    }
529
530    /// Decompresses a Huffman encoded block.
531    fn decompress_huffmann_encoded_block(
532        &self,
533        bitstream: &mut DeflateBitstream,
534        literals_huffman_tree: &HuffmanTree,
535        distances_huffman_tree: &HuffmanTree,
536        uncompressed_data: &mut [u8],
537        uncompressed_data_offset: &mut usize,
538        uncompressed_data_size: usize,
539    ) -> Result<(), ErrorTrace> {
540        let mut data_offset: usize = *uncompressed_data_offset;
541
542        let mediator = Mediator::current();
543        if mediator.debug_output {
544            mediator.debug_print(format!(
545                "DeflateContext::decompress_huffmann_encoded_block {{\n"
546            ));
547        }
548        loop {
549            let mut symbol: u16 = literals_huffman_tree.decode_symbol(bitstream)?;
550
551            if mediator.debug_output {
552                mediator.debug_print(format!("    uncompressed_data_offset: {},\n", data_offset));
553                mediator.debug_print(format!("    symbol: {},\n", symbol));
554            }
555            if symbol == 256 {
556                break;
557            }
558            if symbol < 256 {
559                if data_offset >= uncompressed_data_size {
560                    return Err(keramics_core::error_trace_new!(
561                        "Invalid uncompressed data value too small"
562                    ));
563                }
564                uncompressed_data[data_offset] = symbol as u8;
565
566                data_offset += 1;
567            } else if symbol > 256 && symbol < 286 {
568                symbol -= 257;
569
570                let number_of_extra_bits: u16 =
571                    DEFLATE_LITERAL_CODES_NUMBER_OF_EXTRA_BITS[symbol as usize];
572                let extra_bits: u32 = bitstream.get_value(number_of_extra_bits as usize);
573
574                if mediator.debug_output {
575                    mediator.debug_print(format!("    extra_bits: 0x{:04x},\n", extra_bits));
576                }
577                let compression_size: usize =
578                    ((DEFLATE_LITERAL_CODES_BASE[symbol as usize] as u32) + extra_bits) as usize;
579
580                symbol = distances_huffman_tree.decode_symbol(bitstream)?;
581
582                if mediator.debug_output {
583                    mediator.debug_print(format!("    symbol: {},\n", symbol));
584                }
585                let number_of_extra_bits: u16 =
586                    DEFLATE_DISTANCE_CODES_NUMBER_OF_EXTRA_BITS[symbol as usize];
587                let extra_bits: u32 = bitstream.get_value(number_of_extra_bits as usize);
588
589                if mediator.debug_output {
590                    mediator.debug_print(format!("    extra_bits: 0x{:04x},\n", extra_bits));
591                }
592                let compression_offset: usize =
593                    ((DEFLATE_DISTANCE_CODES_BASE[symbol as usize] as u32) + extra_bits) as usize;
594
595                if compression_offset > data_offset {
596                    return Err(keramics_core::error_trace_new!(format!(
597                        "Invalid compression offset: {} value out of bounds",
598                        compression_offset
599                    )));
600                }
601                if compression_size > uncompressed_data_size - data_offset {
602                    return Err(keramics_core::error_trace_new!(format!(
603                        "Invalid compression size: {} value out of bounds",
604                        compression_size
605                    )));
606                }
607                if mediator.debug_output {
608                    mediator
609                        .debug_print(format!("    compression_offset: {},\n", compression_offset));
610                    mediator.debug_print(format!("    compression_size: {},\n", compression_size));
611                }
612                let mut compression_data_offset: usize = data_offset - compression_offset;
613
614                for _ in 0..compression_size {
615                    uncompressed_data[data_offset] = uncompressed_data[compression_data_offset];
616
617                    data_offset += 1;
618                    compression_data_offset += 1;
619                }
620            } else {
621                return Err(keramics_core::error_trace_new!(format!(
622                    "Invalid symbol: {}",
623                    symbol
624                )));
625            }
626        }
627        if mediator.debug_output {
628            mediator.debug_print(format!("}}\n\n"));
629        }
630        *uncompressed_data_offset = data_offset;
631
632        Ok(())
633    }
634}
635
636#[cfg(test)]
637mod tests {
638    use super::*;
639
640    use std::fs;
641
642    fn get_test_data() -> Vec<u8> {
643        return vec![
644            0xdd, 0x5a, 0x6d, 0x73, 0x1b, 0xb7, 0x11, 0xfe, 0xee, 0x5f, 0x81, 0x72, 0xa6, 0x53,
645            0x69, 0xe6, 0x4c, 0x3b, 0x69, 0xd2, 0x36, 0xce, 0x27, 0xc5, 0x92, 0x13, 0xb6, 0x8e,
646            0xa4, 0x11, 0xe5, 0xba, 0x99, 0x4c, 0x3e, 0x80, 0x47, 0x1c, 0x89, 0xfa, 0x78, 0x60,
647            0x81, 0x3b, 0x51, 0xec, 0xaf, 0xef, 0xb3, 0x8b, 0xd7, 0x23, 0x29, 0xd9, 0x9d, 0x7e,
648            0xab, 0xc7, 0x93, 0x98, 0xe4, 0x01, 0x58, 0xec, 0xcb, 0xb3, 0xcf, 0xee, 0xde, 0x0b,
649            0xf1, 0xb9, 0x3f, 0x17, 0x5b, 0x59, 0xaf, 0x95, 0x78, 0xaf, 0x6b, 0xd5, 0x39, 0xf5,
650            0xe2, 0x99, 0x27, 0xff, 0xae, 0xac, 0xd3, 0xa6, 0x13, 0x5f, 0x4f, 0x5f, 0x57, 0xe2,
651            0xaf, 0xb2, 0x1b, 0xa4, 0xdd, 0x8b, 0xaf, 0x5f, 0xbf, 0xfe, 0xe6, 0xc9, 0x45, 0xeb,
652            0xbe, 0xdf, 0xbe, 0x79, 0xf5, 0x6a, 0xb7, 0xdb, 0x4d, 0x25, 0x1f, 0x33, 0x35, 0x76,
653            0xf5, 0xaa, 0xf5, 0x47, 0xb9, 0x57, 0x2f, 0x68, 0xe1, 0xfd, 0xd5, 0xdd, 0xcf, 0x73,
654            0x71, 0x71, 0x7d, 0x29, 0xde, 0xde, 0x5c, 0x5f, 0xce, 0xee, 0x67, 0x37, 0xd7, 0x73,
655            0xf1, 0xee, 0xe6, 0x4e, 0x7c, 0x98, 0x5f, 0x55, 0xe2, 0xee, 0xea, 0xf6, 0xee, 0xe6,
656            0xf2, 0xc3, 0x5b, 0xfa, 0xba, 0xe2, 0xa7, 0x2e, 0x67, 0xf3, 0xfb, 0xbb, 0xd9, 0x0f,
657            0x1f, 0xe8, 0x1b, 0xde, 0xe0, 0xab, 0xa9, 0xb8, 0x54, 0x8d, 0xee, 0x74, 0x0f, 0xe1,
658            0xdc, 0xf4, 0x45, 0x90, 0x66, 0x12, 0x6e, 0x34, 0x11, 0x6e, 0x2d, 0xdb, 0x56, 0x6c,
659            0x94, 0xec, 0x44, 0x8f, 0x9b, 0xf6, 0xca, 0x6e, 0x9c, 0x90, 0xdd, 0x52, 0xd4, 0xa6,
660            0x5b, 0xfa, 0x55, 0xa2, 0x31, 0x56, 0x0c, 0x4e, 0x55, 0xc2, 0xaa, 0xad, 0x35, 0xcb,
661            0xa1, 0xa6, 0xaf, 0xab, 0xb0, 0x15, 0x3d, 0xbb, 0xd4, 0xae, 0xb7, 0x7a, 0x31, 0xd0,
662            0xf7, 0x42, 0x3a, 0xb1, 0xa4, 0x23, 0xd5, 0x52, 0x2c, 0xf6, 0x62, 0xae, 0x6a, 0xbf,
663            0xc9, 0x57, 0xd8, 0xdf, 0x9a, 0x61, 0xb5, 0x16, 0xdf, 0x09, 0xd3, 0xe0, 0x83, 0xc6,
664            0x73, 0xa6, 0x1e, 0x36, 0xaa, 0xeb, 0x0f, 0xe5, 0x32, 0xf6, 0x48, 0xb0, 0xda, 0x6c,
665            0xf7, 0x56, 0xaf, 0xd6, 0xbd, 0x30, 0xbb, 0x4e, 0x59, 0x01, 0x91, 0xb0, 0x50, 0xf7,
666            0x7b, 0x21, 0x87, 0x7e, 0x6d, 0xac, 0xfe, 0x37, 0x9f, 0x17, 0xf6, 0x39, 0xb5, 0xa2,
667            0x5f, 0xcb, 0x5e, 0xe0, 0xd0, 0x95, 0x95, 0x58, 0xd8, 0xad, 0xf8, 0xa1, 0xa0, 0x87,
668            0x42, 0x00, 0xb5, 0x92, 0xad, 0xb8, 0xe2, 0xad, 0x8f, 0x84, 0x18, 0x3a, 0xba, 0x20,
669            0x4b, 0xaf, 0x84, 0xac, 0x79, 0x97, 0x28, 0x05, 0xd4, 0x80, 0x67, 0xc3, 0x36, 0x06,
670            0x0f, 0x04, 0x01, 0xb5, 0x72, 0xfe, 0x68, 0x28, 0xb4, 0xb7, 0xa6, 0xad, 0x84, 0xb4,
671            0x2a, 0x7e, 0x68, 0x59, 0xe8, 0x8a, 0x6e, 0x43, 0xdf, 0x0e, 0xdd, 0x12, 0xcb, 0x6a,
672            0xb3, 0xd9, 0x98, 0x2e, 0xec, 0x14, 0x1e, 0x14, 0x3b, 0xdd, 0xaf, 0xfd, 0x3e, 0xfe,
673            0xc0, 0xa9, 0x78, 0x67, 0x2c, 0xcb, 0xb1, 0x1d, 0xec, 0xd6, 0xc0, 0x63, 0xb2, 0x56,
674            0x93, 0xc1, 0xa3, 0x8d, 0x26, 0x61, 0x97, 0x09, 0x5f, 0xc5, 0x89, 0x33, 0x7d, 0xee,
675            0x97, 0x9a, 0x9d, 0xb2, 0x15, 0xcc, 0x67, 0x61, 0x25, 0x12, 0x42, 0x77, 0xfe, 0xdf,
676            0x95, 0xe8, 0x8d, 0xa8, 0x25, 0x8c, 0x4e, 0xcf, 0x85, 0x5d, 0xfc, 0x4f, 0xac, 0x01,
677            0x2b, 0x36, 0xb2, 0x93, 0x2b, 0x45, 0xc6, 0xa3, 0x73, 0xdd, 0x50, 0xaf, 0x83, 0x60,
678            0x95, 0xd8, 0xad, 0x15, 0x5f, 0x1f, 0xd6, 0xe7, 0x73, 0x25, 0xef, 0x5d, 0x6a, 0x66,
679            0xa7, 0xc9, 0x9b, 0xb0, 0xcb, 0x99, 0x86, 0x24, 0x6c, 0x1e, 0xb7, 0xd6, 0x5b, 0xda,
680            0xa9, 0xd1, 0x0d, 0xb4, 0xb9, 0x55, 0xb6, 0xa6, 0xad, 0xcf, 0xbe, 0x7d, 0xfd, 0xfb,
681            0x73, 0x3e, 0xce, 0x40, 0x3d, 0x5e, 0xf1, 0x71, 0xa3, 0xa1, 0x77, 0x3d, 0xb4, 0x4e,
682            0x36, 0x80, 0x99, 0xac, 0x72, 0x71, 0x47, 0x6c, 0xb9, 0x50, 0x1d, 0x94, 0x50, 0x6b,
683            0x98, 0x72, 0xb4, 0x7b, 0x21, 0x67, 0x36, 0xf9, 0x2f, 0x66, 0x98, 0x88, 0x33, 0xac,
684            0xa5, 0x7f, 0xd9, 0xc9, 0x79, 0x69, 0x75, 0xfc, 0x25, 0x9d, 0x3c, 0xe8, 0xe5, 0x40,
685            0x7b, 0x59, 0x51, 0xfa, 0x47, 0xd8, 0x40, 0x3d, 0x42, 0x5a, 0xed, 0x48, 0x10, 0xc8,
686            0xbd, 0xd1, 0xce, 0xb1, 0xc3, 0xb3, 0x9f, 0xf9, 0x20, 0x60, 0xb3, 0x1c, 0xb9, 0xda,
687            0x1c, 0xa7, 0xd5, 0x08, 0x41, 0x84, 0xd7, 0xe6, 0xd0, 0xd3, 0xb6, 0x56, 0x35, 0xca,
688            0x5a, 0x2c, 0xe7, 0x5f, 0x1b, 0xd6, 0xf8, 0x27, 0x3a, 0x62, 0x63, 0x96, 0x1a, 0x57,
689            0x93, 0x1c, 0x55, 0xd1, 0xc0, 0xba, 0xab, 0xdb, 0x81, 0x55, 0x81, 0x20, 0x14, 0x9d,
690            0xe9, 0x45, 0xab, 0x37, 0x9a, 0x4e, 0x87, 0x1d, 0x9d, 0x69, 0xfa, 0x1d, 0xb9, 0x97,
691            0xe3, 0x03, 0x61, 0x94, 0x25, 0xb4, 0x1f, 0x63, 0x8f, 0x37, 0x0a, 0xdb, 0xf8, 0x07,
692            0xaa, 0x18, 0xff, 0x8d, 0x5e, 0x0d, 0x96, 0x7f, 0x87, 0x59, 0x5a, 0x55, 0xc0, 0xc7,
693            0xcd, 0xe2, 0x9f, 0x70, 0x85, 0x63, 0xd1, 0x65, 0xb7, 0xf7, 0xdf, 0xc1, 0x1c, 0x43,
694            0xcb, 0xf1, 0xd1, 0x58, 0xb3, 0xc1, 0x8f, 0xf5, 0x5a, 0x76, 0x90, 0x3a, 0x06, 0x08,
695            0xbc, 0xa2, 0x73, 0xf4, 0xa4, 0x8c, 0x0e, 0xc5, 0xdf, 0xb4, 0xe1, 0x63, 0x23, 0xa4,
696            0xf0, 0xea, 0xe1, 0xed, 0xaa, 0xf1, 0x05, 0xc3, 0x1e, 0x07, 0xd7, 0x44, 0xd8, 0x6c,
697            0x35, 0x05, 0x94, 0x61, 0xe1, 0xc2, 0x35, 0x57, 0xf0, 0x04, 0xdc, 0x01, 0x5f, 0x8f,
698            0x2e, 0x5c, 0xa2, 0x17, 0x6e, 0xfa, 0xe0, 0xd1, 0xdb, 0xd1, 0x3e, 0x3e, 0x76, 0x37,
699            0x6a, 0xa9, 0xa5, 0xe8, 0xf7, 0xdb, 0xf2, 0xda, 0x1f, 0x8d, 0xfd, 0x74, 0x04, 0x0a,
700            0x3b, 0x7c, 0xc9, 0x12, 0x33, 0x0e, 0x91, 0xa7, 0xe5, 0x10, 0xd0, 0x5d, 0xbc, 0x46,
701            0x0a, 0x00, 0xaf, 0xba, 0x70, 0xad, 0x8d, 0x5c, 0x02, 0x48, 0x1e, 0xa4, 0x6e, 0xe5,
702            0xa2, 0x8d, 0xf1, 0x5f, 0xe0, 0x52, 0x45, 0x68, 0x4a, 0x0e, 0x58, 0xcb, 0xe0, 0x4a,
703            0x32, 0xe1, 0x42, 0x44, 0x37, 0xa8, 0x01, 0x0f, 0x27, 0x78, 0xf3, 0x9a, 0xc2, 0xc3,
704            0x9a, 0xd5, 0x2a, 0xfb, 0x9e, 0x72, 0x0b, 0x6b, 0x28, 0x4a, 0x1b, 0xb6, 0x38, 0xc3,
705            0x05, 0xd4, 0xa3, 0xdc, 0x6c, 0x71, 0x32, 0x16, 0x02, 0xda, 0xe1, 0xe6, 0x7e, 0x21,
706            0x3d, 0x79, 0xb1, 0xdd, 0x2a, 0x9c, 0xfc, 0x88, 0x60, 0x6a, 0xcd, 0xee, 0x3c, 0x6b,
707            0xe1, 0x52, 0x59, 0xfd, 0x00, 0x2d, 0x3e, 0x28, 0x41, 0x0a, 0x71, 0x93, 0x43, 0x0f,
708            0xa0, 0x33, 0x4e, 0xeb, 0x20, 0xdc, 0x3e, 0xec, 0xe4, 0x75, 0x10, 0x05, 0x5f, 0x48,
709            0x47, 0xc6, 0xeb, 0x38, 0x14, 0x97, 0x74, 0x06, 0x79, 0x3f, 0xbc, 0xc7, 0x63, 0x15,
710            0x1d, 0xc5, 0xe6, 0xa2, 0x58, 0xd8, 0xad, 0x75, 0xbd, 0x2e, 0xc0, 0x00, 0xc6, 0xea,
711            0x91, 0x03, 0x10, 0x99, 0x56, 0x3d, 0x68, 0x36, 0x25, 0x79, 0x31, 0x54, 0x13, 0xe2,
712            0x44, 0x28, 0x68, 0xd8, 0xd8, 0xf8, 0x09, 0x5b, 0x04, 0x33, 0x97, 0xd1, 0x14, 0x36,
713            0xa3, 0x2c, 0xa7, 0x1c, 0x3c, 0x85, 0xb5, 0x2f, 0x71, 0x98, 0x69, 0x39, 0x28, 0xb0,
714            0x4c, 0xaf, 0x74, 0x87, 0x53, 0x8e, 0x6d, 0x7e, 0x8c, 0xc7, 0x11, 0xa7, 0x9a, 0x51,
715            0xf8, 0x57, 0xe2, 0x50, 0x7d, 0x41, 0x7b, 0xe4, 0xcd, 0xc1, 0x76, 0xbc, 0x7d, 0xc8,
716            0x1a, 0x56, 0x6d, 0xa4, 0x4e, 0xf1, 0xa9, 0xb6, 0xd2, 0xb2, 0xa7, 0x90, 0x5e, 0xf8,
717            0x1a, 0x1b, 0x65, 0x55, 0xbb, 0x47, 0x1c, 0x74, 0x9f, 0x58, 0x71, 0x0b, 0x78, 0x0b,
718            0xf9, 0x49, 0x27, 0x37, 0xea, 0x3c, 0x1a, 0x5d, 0x03, 0x88, 0x6c, 0x23, 0x6b, 0x4e,
719            0x12, 0x55, 0x91, 0x23, 0x93, 0x52, 0x8f, 0x84, 0x22, 0xed, 0x28, 0xd3, 0x64, 0xab,
720            0xbf, 0x25, 0x28, 0x0f, 0x39, 0xfe, 0xa4, 0xc5, 0x0f, 0x63, 0x20, 0x85, 0x6c, 0x71,
721            0x5e, 0x52, 0x60, 0x08, 0xb8, 0x98, 0x4b, 0x93, 0x1c, 0xb4, 0xd9, 0xc8, 0x26, 0xec,
722            0xc3, 0xcb, 0xc0, 0x44, 0xe2, 0x4e, 0xc6, 0xeb, 0x86, 0x57, 0xe1, 0xf7, 0xa7, 0x84,
723            0xaf, 0x8a, 0xa0, 0xe8, 0x09, 0xf5, 0x0d, 0x8e, 0x6e, 0x23, 0x6c, 0xbb, 0x61, 0x01,
724            0xec, 0x08, 0xe0, 0x11, 0x79, 0x07, 0x7b, 0x17, 0x4b, 0xce, 0xe2, 0x85, 0x50, 0xe0,
725            0x83, 0x18, 0xc7, 0x8f, 0x68, 0x45, 0xb4, 0x32, 0xa7, 0xbb, 0x67, 0xb3, 0x45, 0x49,
726            0x54, 0x08, 0x95, 0xf9, 0x78, 0xf2, 0xf7, 0x85, 0x82, 0x32, 0x1b, 0xa8, 0xe2, 0x69,
727            0xf2, 0xf2, 0x65, 0xd9, 0x5e, 0x4c, 0xd2, 0x9d, 0x26, 0x61, 0x2f, 0x9f, 0xef, 0x13,
728            0x2c, 0x63, 0x91, 0x6a, 0x11, 0x80, 0xd6, 0x00, 0x8c, 0x2b, 0xb2, 0xc2, 0x42, 0xb6,
729            0xec, 0x47, 0x3b, 0x4b, 0xeb, 0x3a, 0x26, 0x1f, 0x43, 0x17, 0xb4, 0x2f, 0x28, 0x0a,
730            0x4a, 0xa5, 0xab, 0xac, 0x28, 0xd2, 0x53, 0xef, 0x72, 0xb0, 0xb0, 0xfe, 0x5d, 0xf5,
731            0x6c, 0x2a, 0x4a, 0xd8, 0x55, 0x9e, 0x81, 0xbf, 0x59, 0x26, 0x20, 0xa2, 0x6e, 0x69,
732            0x71, 0x0b, 0x4a, 0x89, 0xdd, 0x8a, 0x94, 0x95, 0xa8, 0x90, 0xdb, 0xbb, 0x5e, 0x6d,
733            0x5c, 0x09, 0xe1, 0xc8, 0xb9, 0x83, 0xa2, 0x14, 0x52, 0x73, 0x8e, 0x0c, 0x4f, 0x78,
734            0xf3, 0x53, 0xe6, 0xf3, 0x6c, 0x25, 0x71, 0xad, 0x52, 0xe9, 0x55, 0x01, 0x23, 0x23,
735            0x2f, 0x28, 0xb4, 0x4d, 0x7a, 0x03, 0xc7, 0xad, 0x07, 0xc7, 0x59, 0x9e, 0x4f, 0xdc,
736            0x30, 0x5e, 0x06, 0x1a, 0xf9, 0x91, 0x11, 0x2f, 0xa7, 0x26, 0xf5, 0x18, 0x95, 0x30,
737            0xbe, 0x6b, 0xf4, 0x47, 0x5c, 0xc5, 0x6d, 0x75, 0x3d, 0x98, 0xc1, 0x21, 0x78, 0x37,
738            0xd2, 0x7e, 0x22, 0xe8, 0xb3, 0x99, 0x1d, 0x45, 0xca, 0xa5, 0x9c, 0x5e, 0x75, 0x8c,
739            0xfd, 0x70, 0x45, 0xb2, 0x11, 0x2b, 0xf6, 0xa4, 0x27, 0x12, 0x58, 0x4d, 0xae, 0xa1,
740            0x6f, 0x29, 0xca, 0x58, 0x9d, 0x4e, 0x8e, 0x43, 0xf8, 0x80, 0x5f, 0xa7, 0x6b, 0xc7,
741            0x08, 0xfc, 0x2c, 0xe5, 0x29, 0x15, 0x48, 0xf8, 0xb8, 0x39, 0x38, 0x54, 0xac, 0x21,
742            0xcc, 0x42, 0xc1, 0x9f, 0x40, 0x19, 0x15, 0x23, 0x39, 0x84, 0x2e, 0xcf, 0xc9, 0x41,
743            0xe8, 0xd4, 0xbf, 0x06, 0xf8, 0x4f, 0x4b, 0xc7, 0xd6, 0x06, 0xfa, 0xf6, 0xe9, 0x9a,
744            0x08, 0x6f, 0x11, 0x7e, 0x1e, 0x88, 0xbe, 0x9e, 0x8a, 0x1f, 0x89, 0x56, 0xd1, 0xb1,
745            0x6f, 0xd3, 0xf5, 0x23, 0xb3, 0x12, 0xf3, 0xc1, 0x27, 0xd7, 0xe0, 0xab, 0x27, 0x8b,
746            0x99, 0x22, 0xcc, 0x4a, 0x54, 0x56, 0xc8, 0x92, 0xa2, 0x50, 0x90, 0x20, 0x08, 0x81,
747            0xcc, 0xcc, 0xe2, 0x98, 0x17, 0x80, 0x1c, 0xe2, 0x96, 0x60, 0x78, 0x5b, 0xd5, 0x43,
748            0x33, 0xd1, 0xfd, 0x00, 0x7d, 0xed, 0x72, 0xa7, 0x89, 0x6b, 0x74, 0xa6, 0x7b, 0xc9,
749            0x96, 0x77, 0xb8, 0x31, 0x7d, 0x7c, 0x09, 0xd6, 0x63, 0x57, 0x54, 0x38, 0x99, 0xbd,
750            0x6c, 0xfb, 0xfd, 0xcb, 0xc6, 0x2a, 0x7c, 0xd2, 0x20, 0x76, 0x0f, 0xa6, 0x26, 0x20,
751            0x3f, 0xca, 0xe6, 0xa1, 0xfe, 0xa3, 0x03, 0x63, 0xb5, 0x85, 0x15, 0x88, 0xb1, 0x2d,
752            0xf9, 0xf1, 0x11, 0xd2, 0x65, 0x38, 0xdf, 0x0e, 0x0b, 0xac, 0x85, 0x16, 0xe1, 0xa8,
753            0xdb, 0x56, 0xc2, 0xd1, 0xd3, 0x37, 0x90, 0xd9, 0xa7, 0x5a, 0xc7, 0xdf, 0x04, 0x62,
754            0x51, 0xd6, 0x6d, 0x25, 0xcd, 0x4f, 0x58, 0xcc, 0x64, 0xf9, 0xe8, 0xc4, 0x13, 0xe9,
755            0x9c, 0xb1, 0xc5, 0x1b, 0xe8, 0x8f, 0x85, 0x81, 0x6e, 0x25, 0x81, 0xee, 0xff, 0x81,
756            0x75, 0xce, 0xb0, 0x4c, 0x6d, 0x7b, 0x0a, 0x30, 0x94, 0x1c, 0x7d, 0xa4, 0x48, 0x10,
757            0xd0, 0xf9, 0x82, 0xe8, 0x5c, 0x6c, 0xfd, 0x5d, 0x0b, 0xeb, 0x81, 0xae, 0x63, 0xb3,
758            0xb5, 0x7c, 0x50, 0xcc, 0xf2, 0xa2, 0x40, 0x5c, 0x47, 0x9b, 0xa6, 0x21, 0x9e, 0x87,
759            0x24, 0xa0, 0x5a, 0xc0, 0xaf, 0xff, 0x2f, 0x10, 0xc5, 0xd8, 0xde, 0x1b, 0x26, 0xe1,
760            0x40, 0x20, 0xca, 0x81, 0x15, 0x32, 0xcc, 0xc4, 0x9b, 0x91, 0x0a, 0xbc, 0x8d, 0xe2,
761            0xa9, 0x72, 0xbb, 0x6d, 0xa9, 0xdc, 0x34, 0x1d, 0x8c, 0xce, 0x5a, 0x26, 0xec, 0x0a,
762            0xa2, 0xd5, 0xad, 0xd4, 0xd0, 0xb7, 0x7f, 0xb6, 0xb8, 0x1c, 0xb4, 0xc8, 0x9b, 0x94,
763            0xda, 0x4d, 0xb8, 0xd9, 0x21, 0x7a, 0x9d, 0x93, 0x56, 0x73, 0x74, 0x36, 0x16, 0xe8,
764            0x13, 0x2b, 0x1a, 0xa5, 0x63, 0xee, 0x2b, 0x03, 0xff, 0xcc, 0x9d, 0xa3, 0x0c, 0x36,
765            0x9d, 0x0a, 0x19, 0x11, 0xf0, 0x07, 0x46, 0x92, 0x58, 0x3d, 0x2f, 0x3b, 0x5c, 0x10,
766            0x2f, 0xe4, 0x2b, 0xdc, 0x90, 0x6d, 0x21, 0xbe, 0x27, 0x79, 0x63, 0xe1, 0xc2, 0x11,
767            0x3b, 0x32, 0x45, 0xcc, 0x75, 0x53, 0x31, 0x6b, 0xc8, 0xfe, 0xa9, 0x16, 0x72, 0x40,
768            0x2a, 0xf2, 0xe9, 0x64, 0x94, 0x5e, 0xaf, 0xbc, 0x08, 0x72, 0x25, 0xe9, 0x67, 0x06,
769            0xb9, 0x50, 0xb8, 0x9f, 0xe5, 0x84, 0x95, 0xb8, 0xb5, 0x35, 0xce, 0xbd, 0x64, 0x85,
770            0xd1, 0x35, 0x6a, 0x33, 0x10, 0x7f, 0xf2, 0x9f, 0x61, 0x79, 0x29, 0x5a, 0xb9, 0x73,
771            0x83, 0xee, 0xe9, 0xaa, 0xad, 0x5a, 0xf9, 0x24, 0x00, 0x8d, 0x45, 0xe1, 0x33, 0x27,
772            0x38, 0x40, 0xc5, 0xe7, 0x00, 0x8e, 0x73, 0x82, 0x17, 0xdc, 0x85, 0x52, 0x3b, 0xef,
773            0x53, 0x67, 0xe3, 0xec, 0xe3, 0xb5, 0xa2, 0x3d, 0x36, 0xcc, 0x54, 0xb1, 0x8d, 0xa7,
774            0x62, 0x63, 0x4f, 0x8c, 0x94, 0x29, 0x16, 0xa3, 0x21, 0x52, 0x62, 0xa1, 0x91, 0x63,
775            0x2c, 0xa4, 0xbc, 0xc8, 0xaa, 0x7c, 0x76, 0xa0, 0x10, 0x25, 0xeb, 0x45, 0x5f, 0x91,
776            0x2e, 0x12, 0xb6, 0x25, 0xbe, 0x8c, 0xce, 0x97, 0xb4, 0x8b, 0xdd, 0xa8, 0x4e, 0x5c,
777            0x7a, 0x28, 0xf8, 0x66, 0x2a, 0xee, 0x54, 0xd9, 0x19, 0x9a, 0xf2, 0xd1, 0x1b, 0xb9,
778            0xcf, 0xc8, 0x76, 0x88, 0x42, 0xc0, 0x41, 0x1d, 0xb9, 0xcd, 0x08, 0x8f, 0x9e, 0x61,
779            0x79, 0x6c, 0x12, 0xa2, 0x8d, 0x38, 0x6c, 0x00, 0xc8, 0xb1, 0x1f, 0x11, 0xa3, 0xc1,
780            0xff, 0x4d, 0xca, 0xc8, 0xe3, 0xb2, 0xd9, 0xa7, 0xf0, 0x27, 0x90, 0xac, 0xca, 0xa5,
781            0x10, 0x2b, 0x24, 0xbb, 0xd6, 0x46, 0x29, 0x6f, 0xe5, 0x06, 0xad, 0x1b, 0xb3, 0xf3,
782            0xf9, 0x3d, 0x62, 0xd7, 0x9b, 0x17, 0xa9, 0xae, 0x3a, 0xf7, 0x37, 0x1d, 0xe0, 0x69,
783            0x2b, 0x92, 0x97, 0xc4, 0xf3, 0xf5, 0x06, 0xcc, 0xaa, 0x71, 0x45, 0x02, 0xad, 0x92,
784            0xfa, 0xa6, 0xea, 0x90, 0xfe, 0x1c, 0x5d, 0x54, 0x72, 0x7e, 0x38, 0xac, 0x24, 0xbe,
785            0xe7, 0x34, 0x1a, 0xcf, 0x5c, 0x14, 0x67, 0xfa, 0xc6, 0x4d, 0xa6, 0xd2, 0x54, 0x47,
786            0x51, 0xfd, 0xee, 0x9b, 0x3a, 0x96, 0x5c, 0x08, 0xe5, 0x03, 0x3a, 0x74, 0x5d, 0xac,
787            0x1e, 0x5d, 0x71, 0x3c, 0x41, 0x5c, 0x72, 0x69, 0xda, 0x93, 0x4a, 0xf7, 0x15, 0x2b,
788            0x43, 0xf9, 0x7d, 0xc6, 0x27, 0xd7, 0xc5, 0xc9, 0x56, 0xf5, 0x08, 0xb0, 0x2a, 0xf2,
789            0xe6, 0xa2, 0x84, 0xe7, 0xea, 0x00, 0x12, 0x1d, 0x5e, 0xae, 0x38, 0x38, 0x1d, 0x98,
790            0x1d, 0xa2, 0xa2, 0x08, 0xcb, 0xd9, 0xb1, 0x0a, 0xde, 0x5d, 0x11, 0x2c, 0x2e, 0x15,
791            0xf1, 0xa6, 0xaa, 0x20, 0x13, 0xec, 0xa2, 0x7d, 0x0e, 0xb7, 0x70, 0x37, 0xdf, 0x82,
792            0x38, 0x21, 0xcf, 0x21, 0xa4, 0x8e, 0x99, 0x9b, 0x47, 0xcf, 0xb8, 0x07, 0x0b, 0xb7,
793            0x34, 0x4c, 0x68, 0x91, 0x65, 0xe8, 0x9a, 0xa4, 0x4e, 0x1f, 0x71, 0xb6, 0xcf, 0x89,
794            0x2b, 0x32, 0xf8, 0xc3, 0x8b, 0x8e, 0x95, 0xb6, 0x3c, 0x27, 0xd0, 0x4a, 0xf6, 0x0f,
795            0x85, 0x1f, 0x99, 0x7a, 0x72, 0x7d, 0x73, 0x3f, 0x7b, 0x7b, 0x35, 0x41, 0xf0, 0x3d,
796            0xf6, 0xac, 0x6f, 0x0a, 0xbb, 0x70, 0x06, 0x51, 0xee, 0xe2, 0x9c, 0x32, 0xba, 0x0a,
797            0x08, 0x38, 0x11, 0x29, 0x47, 0x9a, 0x65, 0x7b, 0x15, 0x5b, 0xc5, 0xd2, 0x53, 0xc2,
798            0x86, 0x72, 0xc9, 0x35, 0x66, 0x76, 0x3a, 0x75, 0x52, 0xad, 0x04, 0x4a, 0x92, 0xfa,
799            0xbc, 0xc5, 0x36, 0x01, 0xd4, 0x18, 0x19, 0xfc, 0x45, 0xf8, 0x0a, 0xd5, 0x97, 0xe8,
800            0xb5, 0xd8, 0xe6, 0xb4, 0x86, 0x4f, 0xea, 0x95, 0x9d, 0x0d, 0x7b, 0xb4, 0x4a, 0x3a,
801            0x2a, 0xa7, 0xca, 0x2e, 0x7d, 0x58, 0x92, 0xa3, 0x15, 0xc4, 0x08, 0x87, 0xbe, 0x89,
802            0x62, 0xca, 0x28, 0x63, 0xd6, 0x75, 0xd6, 0xd0, 0xc8, 0xab, 0xdc, 0xb3, 0x32, 0x7c,
803            0x5f, 0x82, 0xf9, 0xc8, 0xc9, 0xca, 0xb8, 0x1e, 0x37, 0xa0, 0x84, 0x6e, 0x32, 0xce,
804            0x50, 0xca, 0x5c, 0xe5, 0x0c, 0x78, 0xbc, 0xbf, 0xb1, 0xd5, 0xb1, 0x96, 0x65, 0xe4,
805            0x7a, 0x45, 0x97, 0x2b, 0xd4, 0x06, 0x27, 0xb4, 0xd4, 0x1c, 0x44, 0x0a, 0x13, 0x08,
806            0x54, 0x80, 0xde, 0x58, 0xd8, 0xd0, 0x2e, 0x5f, 0xd2, 0x25, 0xf7, 0xc9, 0x36, 0x1d,
807            0xf5, 0xe7, 0x50, 0x30, 0x13, 0xb1, 0x50, 0x12, 0x45, 0xe8, 0xfd, 0xda, 0x57, 0x61,
808            0x84, 0x5f, 0xc7, 0x6a, 0x2e, 0xec, 0xcd, 0xe4, 0xc1, 0x97, 0xd2, 0xa9, 0xc9, 0x87,
809            0x1a, 0x22, 0x17, 0xaf, 0xc4, 0x50, 0xc6, 0xe2, 0x84, 0xd8, 0x62, 0xc4, 0xda, 0x8f,
810            0x7a, 0xf3, 0x29, 0x6d, 0xa0, 0x0f, 0x40, 0xff, 0xb6, 0x54, 0xef, 0x94, 0x1e, 0x59,
811            0xec, 0x12, 0x45, 0x0f, 0x1a, 0xfa, 0x92, 0x48, 0xa8, 0xbc, 0xf6, 0x1d, 0x0c, 0x51,
812            0xde, 0x89, 0xeb, 0x29, 0x6a, 0x6f, 0x2c, 0x97, 0x68, 0x83, 0x0d, 0x9b, 0x48, 0x5b,
813            0x47, 0x1e, 0x13, 0x81, 0xc5, 0xd7, 0x7f, 0xd1, 0x9c, 0x87, 0x98, 0xc6, 0x0a, 0x8e,
814            0x4d, 0x0c, 0xa8, 0xe1, 0x64, 0x30, 0x71, 0xb7, 0x0a, 0x35, 0x93, 0xe7, 0x01, 0x76,
815            0x38, 0xf4, 0x3f, 0xaf, 0x98, 0xa7, 0xe6, 0x16, 0x27, 0x55, 0x94, 0xab, 0x0a, 0xa6,
816            0xad, 0xdc, 0xac, 0xf7, 0x04, 0xe0, 0xa0, 0xf1, 0x55, 0x98, 0x82, 0x36, 0x09, 0xf7,
817            0x28, 0x45, 0xa6, 0x96, 0x9c, 0x26, 0xd6, 0x3a, 0x62, 0xb9, 0x27, 0x18, 0x7c, 0x6e,
818            0xed, 0x9d, 0x18, 0x19, 0xf9, 0x6d, 0x8a, 0x59, 0x91, 0x69, 0x4e, 0x48, 0x53, 0xe5,
819            0xb0, 0x69, 0xb8, 0x58, 0xdc, 0x3f, 0x51, 0x8a, 0x94, 0xdd, 0xb9, 0x14, 0x4a, 0xbc,
820            0x1f, 0x1d, 0x5d, 0x74, 0xf3, 0xb2, 0x00, 0x47, 0xd3, 0xaa, 0x51, 0x16, 0x4e, 0xac,
821            0x9b, 0x7a, 0xc9, 0x4c, 0xa5, 0xc9, 0x8f, 0x46, 0x6d, 0x99, 0x54, 0xa9, 0x1c, 0x54,
822            0x02, 0x23, 0x83, 0x7c, 0xcb, 0xc5, 0x4e, 0x98, 0x04, 0xf8, 0x5a, 0x35, 0xb3, 0x40,
823            0x37, 0x15, 0x1f, 0x3a, 0x64, 0x51, 0xc7, 0x46, 0x53, 0x8f, 0x38, 0xa8, 0xd6, 0x54,
824            0xfe, 0xf2, 0x8e, 0xc5, 0x80, 0x24, 0xf5, 0x37, 0xf6, 0x87, 0x2c, 0xb2, 0x68, 0x66,
825            0x15, 0x6d, 0xac, 0x27, 0x5b, 0x57, 0x99, 0xe9, 0xd3, 0x89, 0x87, 0x8d, 0x1c, 0x4f,
826            0xf5, 0x16, 0x65, 0xf7, 0xf9, 0xbf, 0x29, 0xcd, 0x02, 0xcd, 0x62, 0x31, 0x0b, 0x87,
827            0xf1, 0x5b, 0x78, 0xea, 0xba, 0x8c, 0xd3, 0x47, 0xbf, 0x1e, 0x3d, 0x0a, 0x5a, 0x94,
828            0xa6, 0x37, 0x9c, 0x5f, 0x16, 0xc6, 0x17, 0x65, 0x14, 0xb6, 0x2b, 0x2e, 0xef, 0x28,
829            0x8d, 0xb0, 0x68, 0x6e, 0x40, 0x3a, 0x40, 0x6f, 0x58, 0xf9, 0x41, 0x10, 0x85, 0x41,
830            0x61, 0x92, 0x70, 0x90, 0x67, 0x17, 0xbe, 0x41, 0x0a, 0x2d, 0xa6, 0x92, 0x68, 0x85,
831            0x9a, 0x8e, 0x1d, 0x7f, 0x1f, 0x22, 0x84, 0x2b, 0x32, 0x8c, 0x6c, 0xea, 0x02, 0xe2,
832            0x19, 0x78, 0x93, 0x42, 0x2c, 0xfa, 0x1d, 0xd6, 0xcf, 0x95, 0x0e, 0x6b, 0x8f, 0x30,
833            0x0b, 0xf8, 0x13, 0xa0, 0x30, 0x12, 0x10, 0x47, 0xb0, 0x58, 0xf0, 0xe8, 0xa5, 0x61,
834            0xe4, 0xec, 0x3d, 0xe5, 0x2e, 0x26, 0x42, 0xa4, 0xf8, 0x30, 0x50, 0xf3, 0xf4, 0x25,
835            0x8e, 0x31, 0xd0, 0xa9, 0x75, 0x05, 0xa3, 0xa1, 0xae, 0x97, 0xb2, 0x0f, 0xd4, 0xd3,
836            0x0f, 0x1f, 0x21, 0x53, 0xf0, 0x61, 0xff, 0x70, 0x74, 0xda, 0x28, 0x71, 0x95, 0xbb,
837            0x4e, 0xa1, 0x4c, 0xb5, 0xe8, 0xa9, 0xe8, 0x30, 0x3d, 0xa2, 0x84, 0xee, 0x60, 0x13,
838            0x4a, 0xe9, 0x6c, 0x52, 0x24, 0x7e, 0xb3, 0xa1, 0xf1, 0x34, 0x49, 0x03, 0x2d, 0x83,
839            0x77, 0xd4, 0xb8, 0x60, 0x30, 0x45, 0x2a, 0x3a, 0xa8, 0x53, 0x7b, 0xd4, 0x9f, 0x8d,
840            0xd1, 0x14, 0xed, 0x16, 0xb2, 0xc1, 0x89, 0x14, 0xe0, 0x35, 0xf5, 0x67, 0xcc, 0x9f,
841            0xd1, 0x38, 0xa3, 0xd2, 0x89, 0x86, 0xb6, 0x8d, 0xf8, 0x08, 0xfe, 0x09, 0xbd, 0xec,
842            0x53, 0x10, 0x24, 0x51, 0x17, 0x7b, 0x5f, 0xc0, 0x72, 0xe5, 0x4d, 0x25, 0x56, 0x86,
843            0x01, 0xb6, 0x22, 0x17, 0x2f, 0xb9, 0x0b, 0x56, 0x65, 0x83, 0x85, 0xd8, 0x77, 0x59,
844            0xd4, 0x33, 0x92, 0x95, 0x9a, 0x06, 0x87, 0x25, 0x6a, 0xf9, 0x34, 0xb5, 0x2f, 0x47,
845            0xc6, 0x3d, 0xa7, 0xbe, 0x16, 0x20, 0x7f, 0x72, 0x31, 0x17, 0xb3, 0xf9, 0x44, 0xfc,
846            0x70, 0x31, 0x9f, 0xcd, 0xa3, 0x72, 0x3f, 0xce, 0xee, 0x7f, 0xba, 0xf9, 0x70, 0x2f,
847            0x3e, 0x5e, 0xdc, 0xdd, 0x5d, 0x5c, 0xdf, 0xcf, 0xae, 0xe6, 0x02, 0x73, 0xf8, 0x62,
848            0x2c, 0x7f, 0xf3, 0x0e, 0x23, 0xf8, 0x5f, 0xc4, 0xdf, 0x66, 0xd7, 0x97, 0xa0, 0x3b,
849            0xda, 0x4f, 0x80, 0x1f, 0xa9, 0x3b, 0xea, 0xf2, 0x4d, 0x34, 0xe3, 0xca, 0xb2, 0x68,
850            0x93, 0xe6, 0x08, 0xe2, 0x3e, 0xa9, 0x8c, 0x38, 0x85, 0xa6, 0xba, 0x57, 0x15, 0x17,
851            0x44, 0xf6, 0x18, 0x62, 0xa1, 0xcc, 0xfb, 0xd9, 0xfd, 0x7b, 0xbc, 0x07, 0x70, 0x7d,
852            0x73, 0xfd, 0x72, 0x76, 0xfd, 0xee, 0x6e, 0x76, 0xfd, 0xe3, 0xd5, 0xcf, 0x57, 0xd7,
853            0xf7, 0x95, 0xf8, 0xf9, 0xea, 0xee, 0xed, 0x4f, 0x90, 0xf2, 0xe2, 0x87, 0xd9, 0xfb,
854            0xd9, 0xfd, 0x2f, 0xec, 0x42, 0xef, 0x66, 0xf7, 0xd7, 0x57, 0x73, 0xff, 0xfa, 0xc0,
855            0x45, 0xd8, 0xe3, 0xf6, 0xe2, 0x0e, 0x06, 0xfb, 0xf0, 0xfe, 0xe2, 0x4e, 0xdc, 0x7e,
856            0xb8, 0xbb, 0xbd, 0x99, 0x5f, 0xf9, 0x6c, 0xeb, 0xa7, 0x85, 0x2d, 0x4d, 0x16, 0x20,
857            0xff, 0x16, 0x87, 0x6a, 0x9e, 0x3a, 0xf0, 0x64, 0xc6, 0x57, 0x85, 0x63, 0x77, 0x81,
858            0xe5, 0xac, 0xd9, 0x62, 0x02, 0x03, 0x6f, 0xe0, 0x0b, 0x37, 0xf0, 0x2e, 0x7a, 0x84,
859            0xfd, 0x2f, 0x23, 0x6e, 0xd1, 0x2f, 0xf5, 0xdd, 0x46, 0x34, 0x6e, 0x37, 0x5c, 0xab,
860            0x44, 0xb8, 0xd6, 0x8e, 0x91, 0xdd, 0x99, 0x5a, 0xa7, 0x32, 0xd9, 0x83, 0x7a, 0x98,
861            0xb3, 0x72, 0x37, 0xb6, 0x1c, 0xb4, 0x1e, 0x17, 0xb3, 0xde, 0xf7, 0xfe, 0x32, 0xc5,
862            0xe7, 0xa8, 0x52, 0x5a, 0xf4, 0x5e, 0xcb, 0x05, 0xba, 0xcb, 0xe4, 0x7c, 0x33, 0xca,
863            0xbc, 0x02, 0xf4, 0xa7, 0xeb, 0x59, 0x0e, 0xbf, 0x07, 0xbe, 0x6a, 0xb9, 0xd9, 0x09,
864            0x19, 0x51, 0x69, 0x17, 0xad, 0x96, 0x38, 0xc9, 0x82, 0x03, 0xf5, 0x65, 0xcb, 0xa0,
865            0x53, 0xab, 0x56, 0x83, 0x7d, 0xd5, 0xea, 0xbc, 0x4a, 0xd3, 0xee, 0x6a, 0xd4, 0xca,
866            0x4d, 0x9d, 0x9f, 0xcf, 0xfa, 0xfb, 0x99, 0x27, 0x0a, 0xd4, 0xd3, 0x6f, 0xf5, 0x82,
867            0x09, 0x1d, 0x0b, 0xb7, 0xa2, 0x7e, 0x44, 0x9a, 0x5b, 0xc4, 0x23, 0x7b, 0x7a, 0x03,
868            0xc1, 0xf1, 0x74, 0xfc, 0x74, 0x7c, 0x78, 0xf4, 0x1c, 0xa5, 0x0f, 0x6a, 0xca, 0x44,
869            0x93, 0xb5, 0x9a, 0x0f, 0x0e, 0x1d, 0x01, 0x36, 0xad, 0xdc, 0xa0, 0x4b, 0x3e, 0xea,
870            0xe1, 0xd3, 0xea, 0xf8, 0x4a, 0x40, 0x7e, 0x39, 0xc0, 0x6d, 0x15, 0xcd, 0xd6, 0x8b,
871            0xe9, 0x33, 0x02, 0x0a, 0xc4, 0xd6, 0x8f, 0x12, 0x88, 0xc0, 0xf8, 0x9e, 0x2e, 0x0d,
872            0xe4, 0xc2, 0xa6, 0x11, 0xa1, 0xa9, 0xe7, 0x06, 0xb9, 0xa9, 0x5d, 0x6d, 0xfd, 0xcc,
873            0x9c, 0xb2, 0x78, 0xca, 0xd5, 0x34, 0x35, 0x3e, 0x2c, 0x74, 0x59, 0x9b, 0x43, 0xc2,
874            0x98, 0xc1, 0x7f, 0x83, 0xbe, 0x84, 0x37, 0x66, 0x81, 0xab, 0x65, 0xc7, 0xe0, 0xec,
875            0xd9, 0x99, 0x78, 0x94, 0x8a, 0xae, 0xdd, 0x1a, 0xef, 0xb0, 0x2b, 0x63, 0xd0, 0x2a,
876            0x6c, 0xcb, 0xde, 0x21, 0x1a, 0x21, 0xbd, 0xd9, 0x6e, 0x25, 0x75, 0x09, 0x89, 0x13,
877            0x0c, 0x24, 0x78, 0x83, 0x11, 0xc5, 0x60, 0x7d, 0x36, 0x42, 0x0b, 0x7c, 0xe8, 0x32,
878            0xb9, 0xe1, 0x24, 0x78, 0xe2, 0x4d, 0x10, 0x9a, 0x02, 0x90, 0xf3, 0x96, 0xfa, 0xf0,
879            0x07, 0x2b, 0x07, 0xc7, 0x21, 0x3f, 0x24, 0x82, 0x7e, 0xd8, 0x88, 0x0b, 0x7b, 0xa4,
880            0x66, 0xba, 0x5c, 0x62, 0xb8, 0x49, 0x93, 0x82, 0x26, 0xbc, 0xbe, 0x81, 0x08, 0x08,
881            0x4a, 0x88, 0x2f, 0x37, 0x84, 0xed, 0x7d, 0x04, 0x7c, 0x37, 0x15, 0x17, 0x35, 0xe5,
882            0x04, 0xd2, 0x42, 0x44, 0x5e, 0x3a, 0xf9, 0x22, 0x27, 0xea, 0x22, 0x28, 0x3e, 0xae,
883            0x89, 0xba, 0x8f, 0xc3, 0xf5, 0x70, 0x58, 0xf8, 0xec, 0xb8, 0x2d, 0xb2, 0xd0, 0x7a,
884            0x6d, 0x8c, 0xef, 0x82, 0x72, 0xa7, 0x73, 0x34, 0x6c, 0xe7, 0x9e, 0x2b, 0x78, 0x5b,
885            0xa3, 0x18, 0x4f, 0x00, 0x75, 0x2c, 0xa1, 0xec, 0x6a, 0xe5, 0x2f, 0xb1, 0xf5, 0x6d,
886            0xd0, 0x80, 0x7e, 0x7b, 0xf6, 0x3b, 0xb5, 0xe9, 0xe8, 0xd5, 0x92, 0xdc, 0x10, 0xf3,
887            0x6a, 0x6d, 0xa3, 0xec, 0x98, 0xf9, 0xb7, 0xa1, 0x0b, 0xc5, 0xbc, 0xe5, 0x15, 0xc1,
888            0x0e, 0x31, 0x5f, 0x3f, 0x6a, 0xc1, 0x7d, 0x28, 0x5e, 0x42, 0x7d, 0xa5, 0xdd, 0x68,
889            0xdc, 0x83, 0x02, 0xe3, 0x27, 0xbc, 0x07, 0xf3, 0x40, 0x6f, 0xc2, 0x50, 0x51, 0x95,
890            0x14, 0xc6, 0xfa, 0x2c, 0x36, 0xce, 0xf7, 0xe3, 0x37, 0x5a, 0xba, 0xb6, 0x98, 0x86,
891            0x24, 0xce, 0x1d, 0xc6, 0x22, 0xdc, 0xc4, 0x0d, 0x5f, 0x13, 0x90, 0x66, 0x18, 0x65,
892            0x79, 0x99, 0xe9, 0xe4, 0x29, 0x4a, 0x46, 0xf4, 0xdc, 0x29, 0x2a, 0xdc, 0x20, 0xf4,
893            0x84, 0xa9, 0x66, 0xd2, 0x8d, 0xc7, 0x67, 0x0a, 0x78, 0x1f, 0xef, 0xac, 0x9b, 0x26,
894            0xe9, 0x06, 0xe3, 0x40, 0x94, 0x2b, 0x7e, 0x05, 0x98, 0xf1, 0xf2, 0x44, 0xeb, 0x5c,
895            0xda, 0x0d, 0x23, 0x51, 0x24, 0xd7, 0x49, 0x8b, 0x39, 0x9c, 0x07, 0x6b, 0xf3, 0xb4,
896            0x2c, 0x74, 0x8e, 0x81, 0xc9, 0xa8, 0xca, 0xa9, 0x58, 0xf5, 0x4d, 0xd4, 0xea, 0xb8,
897            0x6f, 0xbc, 0xd8, 0x07, 0xb2, 0x91, 0x2f, 0xb4, 0x27, 0x0d, 0x64, 0x9d, 0x26, 0x32,
898            0xbf, 0x2b, 0xbc, 0xb1, 0xa0, 0x8d, 0x49, 0x16, 0xef, 0xc0, 0x57, 0x78, 0xa7, 0x0d,
899            0x79, 0xf5, 0xd4, 0x6b, 0x70, 0xfc, 0xfb, 0xc5, 0xed, 0x2d, 0x1e, 0x99, 0xfd, 0xe3,
900            0x0d, 0x99, 0x90, 0xbb, 0x05, 0x40, 0xd4, 0x7d, 0x78, 0x7d, 0xa1, 0x7c, 0x75, 0x8f,
901            0x7e, 0x63, 0x51, 0x76, 0x69, 0x96, 0x44, 0xaf, 0xd7, 0x7d, 0xe1, 0x82, 0x2a, 0xbc,
902            0x46, 0x31, 0xee, 0x26, 0x44, 0x5a, 0x6d, 0x10, 0x35, 0x16, 0x65, 0x78, 0x1f, 0xbb,
903            0x1a, 0x55, 0xae, 0xe4, 0xd1, 0x7c, 0x6b, 0x97, 0x0e, 0xbd, 0xe6, 0x1a, 0xc1, 0xee,
904            0x41, 0x7f, 0x41, 0x53, 0x4a, 0x05, 0xcf, 0x9c, 0xfc, 0xfa, 0xdb, 0x24, 0x17, 0x29,
905            0xd4, 0x99, 0x08, 0xd9, 0x6e, 0x1f, 0x9d, 0x89, 0x51, 0x35, 0x54, 0x7d, 0x45, 0x25,
906            0x3d, 0x15, 0x67, 0x97, 0xa6, 0xfb, 0x43, 0x7a, 0x5f, 0xa0, 0x88, 0xd1, 0xb8, 0xf9,
907            0xef, 0xce, 0x05, 0x57, 0xeb, 0x5c, 0xa6, 0x3a, 0xd0, 0x0b, 0x78, 0x02, 0x28, 0x7e,
908            0x92, 0x23, 0x54, 0x07, 0x45, 0xda, 0x2e, 0x66, 0xb3, 0x14, 0x2b, 0x6e, 0x0f, 0x3c,
909            0x7f, 0x4c, 0x83, 0x50, 0x2e, 0xea, 0xbd, 0x00, 0xc0, 0x09, 0x2c, 0x6c, 0x1d, 0x0d,
910            0xa8, 0xfc, 0xd3, 0xa1, 0x4f, 0x1a, 0x51, 0x9c, 0x9f, 0xf5, 0x7e, 0x03, 0x2f, 0x23,
911            0xc6, 0xea, 0xcb, 0x2e, 0xa6, 0x99, 0xdb, 0x98, 0x8c, 0xe3, 0x68, 0x75, 0xa1, 0xf2,
912            0x2b, 0x2b, 0x3c, 0x21, 0x8d, 0x92, 0x38, 0x5a, 0x38, 0x81, 0x70, 0xdc, 0xb8, 0x26,
913            0x0c, 0x9e, 0x50, 0xae, 0x18, 0x4f, 0x3e, 0xc3, 0xcb, 0x2f, 0x24, 0x26, 0x1c, 0x4f,
914            0xa7, 0x79, 0x7c, 0xd0, 0x5c, 0x9c, 0xbb, 0xa6, 0xf6, 0x4c, 0x6e, 0x72, 0x48, 0x5b,
915            0xaf, 0x69, 0x62, 0xed, 0x9d, 0x21, 0x0f, 0x13, 0x7f, 0xdd, 0xe3, 0xcf, 0x6f, 0xe2,
916            0x57, 0x96, 0x1b, 0x72, 0x1e, 0x4c, 0x59, 0x7f, 0xe3, 0xc7, 0x83, 0x93, 0x2c, 0x8b,
917            0x9a, 0x69, 0xec, 0x3e, 0x55, 0xf9, 0x42, 0xa8, 0x38, 0xa3, 0x07, 0xd2, 0x3b, 0x97,
918            0xe7, 0xdf, 0xd3, 0x16, 0xb1, 0x1e, 0x21, 0x20, 0xf0, 0xe9, 0x2b, 0xb4, 0xcf, 0x23,
919            0x8d, 0xd7, 0x5d, 0x28, 0x43, 0x19, 0x1a, 0x93, 0x47, 0x25, 0x8a, 0x53, 0x54, 0xfd,
920            0x66, 0xc1, 0xdd, 0x32, 0x39, 0x6a, 0xd9, 0x45, 0x47, 0x96, 0x7d, 0x74, 0xf7, 0xcf,
921            0xbd, 0x72, 0xfa, 0x1e, 0xdc, 0xfd, 0x7a, 0x7e, 0xf5, 0x12, 0x22, 0xf3, 0x92, 0x2f,
922            0x61, 0xe8, 0x4f, 0x71, 0x8f, 0xf0, 0xce, 0xd9, 0x8b, 0xb2, 0x4b, 0x39, 0xd2, 0x57,
923            0x14, 0x8f, 0x5e, 0x61, 0x28, 0x1e, 0x78, 0x8a, 0x81, 0xff, 0x8f, 0xf4, 0x3b, 0x12,
924            0x6f, 0x56, 0xdb, 0x5c, 0xa9, 0x91, 0x08, 0xd1, 0xc9, 0x99, 0xd6, 0xc0, 0x67, 0x70,
925            0xb5, 0x6e, 0x35, 0xc0, 0xe1, 0x40, 0x09, 0x90, 0x16, 0xba, 0xc3, 0x37, 0xfb, 0x42,
926            0xb7, 0x24, 0xf3, 0x75, 0x77, 0x7c, 0xaf, 0xe9, 0x8b, 0xff, 0x00,
927        ];
928    }
929
930    #[test]
931    fn test_bitstream_copy_bytes() -> Result<(), ErrorTrace> {
932        let test_data: [u8; 16] = [
933            0x78, 0xda, 0xbd, 0x59, 0x6d, 0x8f, 0xdb, 0xb8, 0x11, 0xfe, 0x7c, 0xfa, 0x15, 0xc4,
934            0x7e, 0xb9,
935        ];
936        let mut test_bitstream: DeflateBitstream = DeflateBitstream::new(&test_data, 0);
937
938        let test_value: u32 = test_bitstream.get_value(4);
939        assert_eq!(test_value, 0x00000008);
940
941        let mut output_data: [u8; 6] = [0; 6];
942        test_bitstream.copy_bytes(5, &mut output_data, 0, 6)?;
943        assert_eq!(output_data, [0xda, 0xbd, 0x59, 0x6d, 0x8f, 0x00]);
944
945        let test_value: u32 = test_bitstream.get_value(16);
946        assert_eq!(test_value, 0x0000b8db);
947
948        Ok(())
949    }
950
951    #[test]
952    fn test_bitstream_get_value() {
953        let test_data: [u8; 16] = [
954            0x78, 0xda, 0xbd, 0x59, 0x6d, 0x8f, 0xdb, 0xb8, 0x11, 0xfe, 0x7c, 0xfa, 0x15, 0xc4,
955            0x7e, 0xb9,
956        ];
957        let mut test_bitstream: DeflateBitstream = DeflateBitstream::new(&test_data, 0);
958
959        let test_value: u32 = test_bitstream.get_value(0);
960        assert_eq!(test_value, 0);
961
962        let test_value: u32 = test_bitstream.get_value(4);
963        assert_eq!(test_value, 0x00000008);
964
965        let test_value: u32 = test_bitstream.get_value(12);
966        assert_eq!(test_value, 0x00000da7);
967
968        let test_value: u32 = test_bitstream.get_value(32);
969        assert_eq!(test_value, 0x8f6d59bd);
970
971        let mut test_bitstream: DeflateBitstream = DeflateBitstream::new(&test_data, 0);
972
973        let test_value: u32 = test_bitstream.get_value(12);
974        assert_eq!(test_value, 0x000000a78);
975
976        let test_value: u32 = test_bitstream.get_value(32);
977        assert_eq!(test_value, 0xf6d59bdd);
978    }
979
980    #[test]
981    fn test_bitstream_skip_bits() {
982        let test_data: [u8; 16] = [
983            0x78, 0xda, 0xbd, 0x59, 0x6d, 0x8f, 0xdb, 0xb8, 0x11, 0xfe, 0x7c, 0xfa, 0x15, 0xc4,
984            0x7e, 0xb9,
985        ];
986        let mut test_bitstream: DeflateBitstream = DeflateBitstream::new(&test_data, 0);
987
988        test_bitstream.skip_bits(4);
989        let test_value: u32 = test_bitstream.get_value(12);
990        assert_eq!(test_value, 0x00000da7);
991    }
992
993    #[test]
994    fn test_build_dynamic_huffman_trees() -> Result<(), ErrorTrace> {
995        let test_data: Vec<u8> = get_test_data();
996        let mut test_context: DeflateContext = DeflateContext::new();
997
998        let mut test_bitstream: DeflateBitstream = DeflateBitstream::new(&test_data, 0);
999
1000        let mut test_literals_huffman_tree: HuffmanTree = HuffmanTree::new(288, 15);
1001        let mut test_distances_huffman_tree: HuffmanTree = HuffmanTree::new(30, 15);
1002
1003        // Read the block header.
1004        let test_value: u32 = test_bitstream.get_value(3);
1005        assert_eq!(test_value, 0x00000005);
1006
1007        test_context.build_dynamic_huffman_trees(
1008            &mut test_bitstream,
1009            &mut test_literals_huffman_tree,
1010            &mut test_distances_huffman_tree,
1011        )?;
1012        Ok(())
1013    }
1014
1015    #[test]
1016    fn test_decompress() -> Result<(), ErrorTrace> {
1017        let mut test_context: DeflateContext = DeflateContext::new();
1018
1019        let test_data: Vec<u8> = get_test_data();
1020        let mut uncompressed_data: Vec<u8> = vec![0; 11358];
1021        test_context.decompress(&test_data, &mut uncompressed_data)?;
1022        assert_eq!(test_context.uncompressed_data_size, 11358);
1023
1024        let expected_data: Vec<u8> = match fs::read("../LICENSE") {
1025            Ok(data) => data,
1026            Err(error) => {
1027                return Err(keramics_core::error_trace_new_with_error!(
1028                    "Unable read test reference file",
1029                    error
1030                ));
1031            }
1032        };
1033        assert_eq!(&uncompressed_data, &expected_data);
1034
1035        Ok(())
1036    }
1037}