diff --git a/src/pdb/mod.rs b/src/pdb/mod.rs index d53e513..a1de9bd 100644 --- a/src/pdb/mod.rs +++ b/src/pdb/mod.rs @@ -186,9 +186,6 @@ impl Header { /// Each page consists of a header that contains information about the type, number of rows, etc., /// followed by the data section that holds the row data. Each row needs to be located using an /// offset found in the page footer at the end of the page. -/// -/// **Note: The `Page` struct is currently not writable, because row offsets are not taken into -/// account and rows are not serialized correctly yet.** #[binread] #[derive(Debug, PartialEq)] #[br(little, magic = 0u32)] @@ -273,12 +270,6 @@ pub struct Page { // (currently nightly-only, see https://github.com/rust-lang/rust/issues/88581). #[br(calc = if num_rows > 0 { (num_rows - 1) / RowGroup::MAX_ROW_COUNT + 1 } else { 0 })] num_row_groups: u16, - /// The offset at which row groups for this page are located. - /// - /// **Note:** This is a virtual field and not actually read from the file. - #[br(temp)] - #[br(calc = SeekFrom::Current(i64::from(page_size) - i64::from(Self::HEADER_SIZE) - i64::from(num_rows) * 2 - i64::from(num_row_groups) * 4))] - row_groups_offset: SeekFrom, /// The offset at which the row data for this page are located. /// /// **Note:** This is a virtual field and not actually read from the file. @@ -286,15 +277,93 @@ pub struct Page { #[br(calc = page_index.offset(page_size) + u64::from(Self::HEADER_SIZE))] page_heap_offset: u64, /// Row groups belonging to this page. - #[br(seek_before(row_groups_offset), restore_position)] + #[br(seek_before(SeekFrom::Current(Page::row_groups_offset( + page_size, + num_rows_small, + num_rows_large + ))))] #[br(parse_with = Self::parse_row_groups, args(page_type, page_heap_offset, num_rows, num_row_groups))] pub row_groups: Vec, } +impl BinWrite for Page { + type Args = (u32,); + + fn write_options( + &self, + writer: &mut W, + options: &WriteOptions, + args: Self::Args, + ) -> BinResult<()> { + let options = &options.clone().with_endian(Endian::Little); + + let page_offset = writer.stream_position().map_err(binrw::Error::Io)?; + + // Header + 0u32.write_options(writer, options, ())?; + self.page_index.write_options(writer, options, ())?; + self.page_type.write_options(writer, options, ())?; + self.next_page.write_options(writer, options, ())?; + self.unknown1.write_options(writer, options, ())?; + self.unknown2.write_options(writer, options, ())?; + self.num_rows_small.write_options(writer, options, ())?; + self.unknown3.write_options(writer, options, ())?; + self.unknown4.write_options(writer, options, ())?; + self.page_flags.write_options(writer, options, ())?; + self.free_size.write_options(writer, options, ())?; + self.used_size.write_options(writer, options, ())?; + self.unknown5.write_options(writer, options, ())?; + self.num_rows_large.write_options(writer, options, ())?; + self.unknown6.write_options(writer, options, ())?; + self.unknown7.write_options(writer, options, ())?; + + let (page_size,) = args; + + // Padding + let page_heap_size: usize = + Self::row_groups_offset(page_size, self.num_rows_small, self.num_rows_large) + .try_into() + .map_err(|e| binrw::Error::Custom { + pos: (page_offset + u64::from(Self::HEADER_SIZE)), + err: Box::new(e), + })?; + vec![0u8; page_heap_size].write_options(writer, options, ())?; + + // Row Groups + let mut relative_row_offset: u64 = Self::HEADER_SIZE.into(); + for row_group in &self.row_groups { + relative_row_offset = row_group.write_options_and_get_row_offset( + writer, + options, + (page_offset, relative_row_offset), + )?; + } + Ok(()) + } +} + impl Page { /// Size of the page header in bytes. pub const HEADER_SIZE: u32 = 0x28; + fn row_groups_offset(page_size: u32, num_rows_small: u8, num_rows_large: u16) -> i64 { + let num_rows = if num_rows_large > num_rows_small.into() && num_rows_large != 0x1fff { + num_rows_large + } else { + num_rows_small.into() + }; + let num_row_groups = if num_rows > 0 { + (num_rows - 1) / RowGroup::MAX_ROW_COUNT + 1 + } else { + 0 + }; + + let row_groups_size = num_rows * 2 + num_row_groups * 4; + dbg!(row_groups_size); + + i64::from(page_size) - i64::from(Self::HEADER_SIZE) - i64::from(row_groups_size) + } + /// Parse the row groups at the end of the page. fn parse_row_groups( reader: &mut R, @@ -381,8 +450,8 @@ pub struct RowGroup { /// An offset which points to a row in the table, whose actual presence is controlled by one of the /// bits in `row_present_flags`. This instance allows the row itself to be lazily loaded, unless it /// is not present, in which case there is no content to be loaded. - #[br(offset = page_heap_offset, args { count: num_rows.into(), inner: (page_type,) })] - rows: Vec>, + #[br(offset = page_heap_offset, parse_with = FilePtr16::parse, args { count: num_rows.into(), inner: (page_type,) })] + rows: Vec, row_presence_flags: u16, /// Unknown field, probably padding. /// @@ -395,17 +464,68 @@ impl RowGroup { /// Return the ordered list of row offsets that are actually present. pub fn present_rows(&self) -> impl Iterator { - self.rows - .iter() - .rev() - .enumerate() - .filter_map(|(i, row_offset)| { - if (self.row_presence_flags & (1 << i)) != 0 { - row_offset.value.as_ref() - } else { - None - } - }) + self.rows.iter().rev().enumerate().filter_map(|(i, row)| { + if (self.row_presence_flags & (1 << i)) != 0 { + Some(row) + } else { + None + } + }) + } + + fn write_options_and_get_row_offset( + &self, + writer: &mut W, + options: &WriteOptions, + args: (u64, u64), + ) -> binrw::BinResult { + let options = &options.clone().with_endian(Endian::Little); + + let (page_offset, relative_row_offset) = args; + + // Write rows + let mut offset = page_offset + relative_row_offset; + for row in &self.rows { + // Write row offset + let row_offset: u16 = offset + .checked_sub(page_offset) + .and_then(|v| u16::try_from(v).ok()) + .ok_or_else(|| binrw::Error::AssertFail { + pos: 0, + message: "Wraparound while calculating row offset".to_string(), + })?; + row_offset.write_options(writer, options, ())?; + let restore_position = writer.stream_position()?; + + // Write actual row content + let offset_before_write = writer.seek(SeekFrom::Start(offset))?; + row.write_options(writer, options, ())?; + let offset_after_write = writer.stream_position()?; + offset += offset_after_write - offset_before_write; + + // Seek back to row offset + writer.seek(SeekFrom::Start(restore_position))?; + } + let new_relative_row_offset = offset - page_offset; + + self.row_presence_flags.write_options(writer, options, ())?; + self.unknown.write_options(writer, options, ())?; + + Ok(new_relative_row_offset) + } +} + +impl BinWrite for RowGroup { + type Args = (u64, u64); + + fn write_options( + &self, + writer: &mut W, + options: &WriteOptions, + args: Self::Args, + ) -> binrw::BinResult<()> { + self.write_options_and_get_row_offset(writer, options, args)?; + Ok(()) } } @@ -872,7 +992,7 @@ pub enum Row { #[cfg(test)] mod test { use super::*; - use crate::util::testing::test_roundtrip; + use crate::util::testing::{test_roundtrip, test_roundtrip_with_args}; #[test] fn empty_header() { @@ -1184,4 +1304,634 @@ mod test { }; test_roundtrip(&[0, 0, 0, 0, 1, 1, 0, 0, 11, 80, 105, 110, 107], row); } + + #[test] + fn track_page() { + let page = Page { + page_index: PageIndex(2), + page_type: PageType::Tracks, + next_page: PageIndex(47), + unknown1: 32, + unknown2: 0, + num_rows_small: 7, + unknown3: 64, + unknown4: 0, + page_flags: 52, + free_size: 1530, + used_size: 2508, + unknown5: 1, + num_rows_large: 6, + unknown6: 0, + unknown7: 0, + row_groups: vec![RowGroup { + rows: vec![ + Row::Track(Track { + unknown1: 36, + index_shift: 192, + bitmask: 788224, + sample_rate: 44100, + composer_id: 0, + file_size: 5124342, + unknown2: 263879995, + unknown3: 64128, + unknown4: 1511, + artwork_id: 0, + key_id: 5, + orig_artist_id: 0, + label_id: 1, + remixer_id: 0, + bitrate: 320, + track_number: 0, + tempo: 12000, + genre_id: 0, + album_id: 0, + artist_id: 1, + id: 2, + disc_number: 0, + play_count: 0, + year: 0, + sample_depth: 16, + duration: 128, + unknown5: 41, + color: ColorIndex::None, + rating: 0, + unknown6: 1, + unknown7: 3, + isrc: DeviceSQLString::new_isrc("".to_string()).unwrap(), + unknown_string1: DeviceSQLString::empty(), + unknown_string2: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string3: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string4: DeviceSQLString::empty(), + message: DeviceSQLString::empty(), + kuvo_public: DeviceSQLString::empty(), + autoload_hotcues: DeviceSQLString::new("ON".to_string()).unwrap(), + unknown_string5: DeviceSQLString::empty(), + unknown_string6: DeviceSQLString::empty(), + date_added: DeviceSQLString::new("2018-05-25".to_string()).unwrap(), + release_date: DeviceSQLString::empty(), + mix_name: DeviceSQLString::empty(), + unknown_string7: DeviceSQLString::empty(), + analyze_path: DeviceSQLString::new( + "/PIONEER/USBANLZ/P053/0001D21F/ANLZ0000.DAT".to_string(), + ) + .unwrap(), + analyze_date: DeviceSQLString::new("2022-02-02".to_string()).unwrap(), + comment: DeviceSQLString::new("Tracks by www.loopmasters.com".to_string()) + .unwrap(), + title: DeviceSQLString::new("Demo Track 2".to_string()).unwrap(), + unknown_string8: DeviceSQLString::empty(), + filename: DeviceSQLString::new("Demo Track 2.mp3".to_string()).unwrap(), + file_path: DeviceSQLString::new( + "/Contents/Loopmasters/UnknownAlbum/Demo Track 2.mp3".to_string(), + ) + .unwrap(), + }), + Row::Track(Track { + unknown1: 36, + index_shift: 160, + bitmask: 788224, + sample_rate: 44100, + composer_id: 0, + file_size: 6899624, + unknown2: 214020570, + unknown3: 64128, + unknown4: 1511, + artwork_id: 0, + key_id: 5, + orig_artist_id: 0, + label_id: 1, + remixer_id: 0, + bitrate: 320, + track_number: 0, + tempo: 12800, + genre_id: 0, + album_id: 0, + artist_id: 1, + id: 1, + disc_number: 0, + play_count: 0, + year: 0, + sample_depth: 16, + duration: 172, + unknown5: 41, + color: ColorIndex::None, + rating: 0, + unknown6: 1, + unknown7: 3, + isrc: DeviceSQLString::new_isrc("".to_string()).unwrap(), + unknown_string1: DeviceSQLString::empty(), + unknown_string2: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string3: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string4: DeviceSQLString::empty(), + message: DeviceSQLString::empty(), + kuvo_public: DeviceSQLString::empty(), + autoload_hotcues: DeviceSQLString::new("ON".to_string()).unwrap(), + unknown_string5: DeviceSQLString::empty(), + unknown_string6: DeviceSQLString::empty(), + date_added: DeviceSQLString::new("2018-05-25".to_string()).unwrap(), + release_date: DeviceSQLString::empty(), + mix_name: DeviceSQLString::empty(), + unknown_string7: DeviceSQLString::empty(), + analyze_path: DeviceSQLString::new( + "/PIONEER/USBANLZ/P016/0000875E/ANLZ0000.DAT".to_string(), + ) + .unwrap(), + analyze_date: DeviceSQLString::new("2022-02-02".to_string()).unwrap(), + comment: DeviceSQLString::new("Tracks by www.loopmasters.com".to_string()) + .unwrap(), + title: DeviceSQLString::new("Demo Track 1".to_string()).unwrap(), + unknown_string8: DeviceSQLString::empty(), + filename: DeviceSQLString::new("Demo Track 1.mp3".to_string()).unwrap(), + file_path: DeviceSQLString::new( + "/Contents/Loopmasters/UnknownAlbum/Demo Track 1.mp3".to_string(), + ) + .unwrap(), + }), + Row::Track(Track { + unknown1: 36, + index_shift: 128, + bitmask: 788224, + sample_rate: 44100, + composer_id: 0, + file_size: 6899624, + unknown2: 214020570, + unknown3: 64128, + unknown4: 1511, + artwork_id: 0, + key_id: 5, + orig_artist_id: 0, + label_id: 1, + remixer_id: 0, + bitrate: 320, + track_number: 0, + tempo: 12800, + genre_id: 0, + album_id: 0, + artist_id: 1, + id: 5, + disc_number: 0, + play_count: 0, + year: 0, + sample_depth: 16, + duration: 172, + unknown5: 41, + color: ColorIndex::None, + rating: 0, + unknown6: 1, + unknown7: 3, + isrc: DeviceSQLString::new_isrc("".to_string()).unwrap(), + unknown_string1: DeviceSQLString::empty(), + unknown_string2: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string3: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string4: DeviceSQLString::empty(), + message: DeviceSQLString::empty(), + kuvo_public: DeviceSQLString::empty(), + autoload_hotcues: DeviceSQLString::new("ON".to_string()).unwrap(), + unknown_string5: DeviceSQLString::empty(), + unknown_string6: DeviceSQLString::empty(), + date_added: DeviceSQLString::new("2018-05-25".to_string()).unwrap(), + release_date: DeviceSQLString::empty(), + mix_name: DeviceSQLString::empty(), + unknown_string7: DeviceSQLString::empty(), + analyze_path: DeviceSQLString::new( + "/PIONEER/USBANLZ/P016/0000875E/ANLZ0000.DAT".to_string(), + ) + .unwrap(), + analyze_date: DeviceSQLString::new("2022-02-02".to_string()).unwrap(), + comment: DeviceSQLString::new("Tracks by www.loopmasters.com".to_string()) + .unwrap(), + title: DeviceSQLString::new("Demo Track 1".to_string()).unwrap(), + unknown_string8: DeviceSQLString::empty(), + filename: DeviceSQLString::new("Demo Track 1.mp3".to_string()).unwrap(), + file_path: DeviceSQLString::new( + "/Contents/Loopmasters/UnknownAlbum/Demo Track 1.mp3".to_string(), + ) + .unwrap(), + }), + Row::Track(Track { + unknown1: 36, + index_shift: 96, + bitmask: 788224, + sample_rate: 44100, + composer_id: 0, + file_size: 2010816, + unknown2: 227782126, + unknown3: 64128, + unknown4: 1511, + artwork_id: 0, + key_id: 4, + orig_artist_id: 0, + label_id: 0, + remixer_id: 0, + bitrate: 2116, + track_number: 0, + tempo: 0, + genre_id: 0, + album_id: 0, + artist_id: 0, + id: 4, + disc_number: 0, + play_count: 0, + year: 0, + sample_depth: 24, + duration: 7, + unknown5: 41, + color: ColorIndex::None, + rating: 0, + unknown6: 11, + unknown7: 3, + isrc: DeviceSQLString::new_isrc("".to_string()).unwrap(), + unknown_string1: DeviceSQLString::empty(), + unknown_string2: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string3: DeviceSQLString::new("2".to_string()).unwrap(), + unknown_string4: DeviceSQLString::empty(), + message: DeviceSQLString::empty(), + kuvo_public: DeviceSQLString::empty(), + autoload_hotcues: DeviceSQLString::new("ON".to_string()).unwrap(), + unknown_string5: DeviceSQLString::empty(), + unknown_string6: DeviceSQLString::empty(), + date_added: DeviceSQLString::new("2015-09-07".to_string()).unwrap(), + release_date: DeviceSQLString::empty(), + mix_name: DeviceSQLString::empty(), + unknown_string7: DeviceSQLString::empty(), + analyze_path: DeviceSQLString::new( + "/PIONEER/USBANLZ/P021/00006D2B/ANLZ0000.DAT".to_string(), + ) + .unwrap(), + analyze_date: DeviceSQLString::new("2022-02-02".to_string()).unwrap(), + comment: DeviceSQLString::empty(), + title: DeviceSQLString::new("HORN".to_string()).unwrap(), + unknown_string8: DeviceSQLString::empty(), + filename: DeviceSQLString::new("HORN.wav".to_string()).unwrap(), + file_path: DeviceSQLString::new( + "/Contents/UnknownArtist/UnknownAlbum/HORN.wav".to_string(), + ) + .unwrap(), + }), + Row::Track(Track { + unknown1: 36, + index_shift: 64, + bitmask: 788224, + sample_rate: 44100, + composer_id: 0, + file_size: 1941204, + unknown2: 243638374, + unknown3: 64128, + unknown4: 1511, + artwork_id: 0, + key_id: 3, + orig_artist_id: 0, + label_id: 0, + remixer_id: 0, + bitrate: 2116, + track_number: 0, + tempo: 0, + genre_id: 0, + album_id: 0, + artist_id: 0, + id: 3, + disc_number: 0, + play_count: 0, + year: 0, + sample_depth: 24, + duration: 7, + unknown5: 41, + color: ColorIndex::None, + rating: 0, + unknown6: 11, + unknown7: 3, + isrc: DeviceSQLString::new_isrc("".to_string()).unwrap(), + unknown_string1: DeviceSQLString::empty(), + unknown_string2: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string3: DeviceSQLString::new("2".to_string()).unwrap(), + unknown_string4: DeviceSQLString::empty(), + message: DeviceSQLString::empty(), + kuvo_public: DeviceSQLString::empty(), + autoload_hotcues: DeviceSQLString::new("ON".to_string()).unwrap(), + unknown_string5: DeviceSQLString::empty(), + unknown_string6: DeviceSQLString::empty(), + date_added: DeviceSQLString::new("2015-09-07".to_string()).unwrap(), + release_date: DeviceSQLString::empty(), + mix_name: DeviceSQLString::empty(), + unknown_string7: DeviceSQLString::empty(), + analyze_path: DeviceSQLString::new( + "/PIONEER/USBANLZ/P017/00009B77/ANLZ0000.DAT".to_string(), + ) + .unwrap(), + analyze_date: DeviceSQLString::new("2022-02-02".to_string()).unwrap(), + comment: DeviceSQLString::empty(), + title: DeviceSQLString::new("SIREN".to_string()).unwrap(), + unknown_string8: DeviceSQLString::empty(), + filename: DeviceSQLString::new("SIREN.wav".to_string()).unwrap(), + file_path: DeviceSQLString::new( + "/Contents/UnknownArtist/UnknownAlbum/SIREN.wav".to_string(), + ) + .unwrap(), + }), + Row::Track(Track { + unknown1: 36, + index_shift: 32, + bitmask: 788224, + sample_rate: 44100, + composer_id: 0, + file_size: 1515258, + unknown2: 34882935, + unknown3: 64128, + unknown4: 1511, + artwork_id: 0, + key_id: 2, + orig_artist_id: 0, + label_id: 0, + remixer_id: 0, + bitrate: 2116, + track_number: 0, + tempo: 0, + genre_id: 0, + album_id: 0, + artist_id: 0, + id: 2, + disc_number: 0, + play_count: 0, + year: 0, + sample_depth: 24, + duration: 5, + unknown5: 41, + color: ColorIndex::None, + rating: 0, + unknown6: 11, + unknown7: 3, + isrc: DeviceSQLString::new_isrc("".to_string()).unwrap(), + unknown_string1: DeviceSQLString::empty(), + unknown_string2: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string3: DeviceSQLString::new("2".to_string()).unwrap(), + unknown_string4: DeviceSQLString::empty(), + message: DeviceSQLString::empty(), + kuvo_public: DeviceSQLString::empty(), + autoload_hotcues: DeviceSQLString::new("ON".to_string()).unwrap(), + unknown_string5: DeviceSQLString::empty(), + unknown_string6: DeviceSQLString::empty(), + date_added: DeviceSQLString::new("2015-09-07".to_string()).unwrap(), + release_date: DeviceSQLString::empty(), + mix_name: DeviceSQLString::empty(), + unknown_string7: DeviceSQLString::empty(), + analyze_path: DeviceSQLString::new( + "/PIONEER/USBANLZ/P043/00011517/ANLZ0000.DAT".to_string(), + ) + .unwrap(), + analyze_date: DeviceSQLString::new("2022-02-02".to_string()).unwrap(), + comment: DeviceSQLString::empty(), + title: DeviceSQLString::new("SINEWAVE".to_string()).unwrap(), + unknown_string8: DeviceSQLString::empty(), + filename: DeviceSQLString::new("SINEWAVE.wav".to_string()).unwrap(), + file_path: DeviceSQLString::new( + "/Contents/UnknownArtist/UnknownAlbum/SINEWAVE.wav".to_string(), + ) + .unwrap(), + }), + Row::Track(Track { + unknown1: 36, + index_shift: 0, + bitmask: 788224, + sample_rate: 44100, + composer_id: 0, + file_size: 1382226, + unknown2: 191204207, + unknown3: 64128, + unknown4: 1511, + artwork_id: 0, + key_id: 1, + orig_artist_id: 0, + label_id: 0, + remixer_id: 0, + bitrate: 2116, + track_number: 0, + tempo: 0, + genre_id: 0, + album_id: 0, + artist_id: 0, + id: 1, + disc_number: 0, + play_count: 0, + year: 0, + sample_depth: 24, + duration: 5, + unknown5: 41, + color: ColorIndex::None, + rating: 0, + unknown6: 11, + unknown7: 3, + isrc: DeviceSQLString::new_isrc("".to_string()).unwrap(), + unknown_string1: DeviceSQLString::empty(), + unknown_string2: DeviceSQLString::new("3".to_string()).unwrap(), + unknown_string3: DeviceSQLString::new("2".to_string()).unwrap(), + unknown_string4: DeviceSQLString::empty(), + message: DeviceSQLString::empty(), + kuvo_public: DeviceSQLString::empty(), + autoload_hotcues: DeviceSQLString::new("ON".to_string()).unwrap(), + unknown_string5: DeviceSQLString::empty(), + unknown_string6: DeviceSQLString::empty(), + date_added: DeviceSQLString::new("2015-09-07".to_string()).unwrap(), + release_date: DeviceSQLString::empty(), + mix_name: DeviceSQLString::empty(), + unknown_string7: DeviceSQLString::empty(), + analyze_path: DeviceSQLString::new( + "/PIONEER/USBANLZ/P019/00020AA9/ANLZ0000.DAT".to_string(), + ) + .unwrap(), + analyze_date: DeviceSQLString::new("2022-02-02".to_string()).unwrap(), + comment: DeviceSQLString::empty(), + title: DeviceSQLString::new("NOISE".to_string()).unwrap(), + unknown_string8: DeviceSQLString::empty(), + filename: DeviceSQLString::new("NOISE.wav".to_string()).unwrap(), + file_path: DeviceSQLString::new( + "/Contents/UnknownArtist/UnknownAlbum/NOISE.wav".to_string(), + ) + .unwrap(), + }), + ], + row_presence_flags: 96, + unknown: 64, + }], + }; + + let page_size: u32 = 4096; + test_roundtrip_with_args( + &[ + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 7, 64, 0, + 52, 250, 5, 204, 9, 1, 0, 6, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 7, 12, 0, 68, 172, 0, + 0, 0, 0, 0, 0, 82, 23, 21, 0, 111, 139, 101, 11, 128, 250, 231, 5, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 5, 0, 41, + 0, 0, 0, 11, 0, 3, 0, 136, 0, 137, 0, 138, 0, 140, 0, 142, 0, 143, 0, 144, 0, 145, + 0, 148, 0, 149, 0, 150, 0, 161, 0, 162, 0, 163, 0, 164, 0, 208, 0, 219, 0, 220, 0, + 226, 0, 227, 0, 237, 0, 3, 3, 5, 51, 5, 50, 3, 3, 3, 7, 79, 78, 3, 3, 23, 50, 48, + 49, 53, 45, 48, 57, 45, 48, 55, 3, 3, 3, 89, 47, 80, 73, 79, 78, 69, 69, 82, 47, + 85, 83, 66, 65, 78, 76, 90, 47, 80, 48, 49, 57, 47, 48, 48, 48, 50, 48, 65, 65, 57, + 47, 65, 78, 76, 90, 48, 48, 48, 48, 46, 68, 65, 84, 23, 50, 48, 50, 50, 45, 48, 50, + 45, 48, 50, 3, 13, 78, 79, 73, 83, 69, 3, 21, 78, 79, 73, 83, 69, 46, 119, 97, 118, + 95, 47, 67, 111, 110, 116, 101, 110, 116, 115, 47, 85, 110, 107, 110, 111, 119, + 110, 65, 114, 116, 105, 115, 116, 47, 85, 110, 107, 110, 111, 119, 110, 65, 108, + 98, 117, 109, 47, 78, 79, 73, 83, 69, 46, 119, 97, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 32, 0, 0, 7, 12, 0, 68, 172, 0, + 0, 0, 0, 0, 0, 250, 30, 23, 0, 119, 69, 20, 2, 128, 250, 231, 5, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 5, 0, 41, 0, + 0, 0, 11, 0, 3, 0, 136, 0, 137, 0, 138, 0, 140, 0, 142, 0, 143, 0, 144, 0, 145, 0, + 148, 0, 149, 0, 150, 0, 161, 0, 162, 0, 163, 0, 164, 0, 208, 0, 219, 0, 220, 0, + 229, 0, 230, 0, 243, 0, 3, 3, 5, 51, 5, 50, 3, 3, 3, 7, 79, 78, 3, 3, 23, 50, 48, + 49, 53, 45, 48, 57, 45, 48, 55, 3, 3, 3, 89, 47, 80, 73, 79, 78, 69, 69, 82, 47, + 85, 83, 66, 65, 78, 76, 90, 47, 80, 48, 52, 51, 47, 48, 48, 48, 49, 49, 53, 49, 55, + 47, 65, 78, 76, 90, 48, 48, 48, 48, 46, 68, 65, 84, 23, 50, 48, 50, 50, 45, 48, 50, + 45, 48, 50, 3, 19, 83, 73, 78, 69, 87, 65, 86, 69, 3, 27, 83, 73, 78, 69, 87, 65, + 86, 69, 46, 119, 97, 118, 101, 47, 67, 111, 110, 116, 101, 110, 116, 115, 47, 85, + 110, 107, 110, 111, 119, 110, 65, 114, 116, 105, 115, 116, 47, 85, 110, 107, 110, + 111, 119, 110, 65, 108, 98, 117, 109, 47, 83, 73, 78, 69, 87, 65, 86, 69, 46, 119, + 97, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 36, 0, 64, 0, 0, 7, 12, 0, 68, 172, 0, 0, 0, 0, 0, 0, 212, 158, 29, 0, 102, + 160, 133, 14, 128, 250, 231, 5, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 68, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 7, 0, 41, 0, 0, 0, 11, 0, 3, 0, 136, 0, 137, + 0, 138, 0, 140, 0, 142, 0, 143, 0, 144, 0, 145, 0, 148, 0, 149, 0, 150, 0, 161, 0, + 162, 0, 163, 0, 164, 0, 208, 0, 219, 0, 220, 0, 226, 0, 227, 0, 237, 0, 3, 3, 5, + 51, 5, 50, 3, 3, 3, 7, 79, 78, 3, 3, 23, 50, 48, 49, 53, 45, 48, 57, 45, 48, 55, 3, + 3, 3, 89, 47, 80, 73, 79, 78, 69, 69, 82, 47, 85, 83, 66, 65, 78, 76, 90, 47, 80, + 48, 49, 55, 47, 48, 48, 48, 48, 57, 66, 55, 55, 47, 65, 78, 76, 90, 48, 48, 48, 48, + 46, 68, 65, 84, 23, 50, 48, 50, 50, 45, 48, 50, 45, 48, 50, 3, 13, 83, 73, 82, 69, + 78, 3, 21, 83, 73, 82, 69, 78, 46, 119, 97, 118, 95, 47, 67, 111, 110, 116, 101, + 110, 116, 115, 47, 85, 110, 107, 110, 111, 119, 110, 65, 114, 116, 105, 115, 116, + 47, 85, 110, 107, 110, 111, 119, 110, 65, 108, 98, 117, 109, 47, 83, 73, 82, 69, + 78, 46, 119, 97, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 36, 0, 96, 0, 0, 7, 12, 0, 68, 172, 0, 0, 0, 0, 0, 0, 192, 174, 30, 0, + 238, 173, 147, 13, 128, 250, 231, 5, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 68, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 7, 0, 41, 0, 0, 0, 11, 0, 3, 0, 136, 0, + 137, 0, 138, 0, 140, 0, 142, 0, 143, 0, 144, 0, 145, 0, 148, 0, 149, 0, 150, 0, + 161, 0, 162, 0, 163, 0, 164, 0, 208, 0, 219, 0, 220, 0, 225, 0, 226, 0, 235, 0, 3, + 3, 5, 51, 5, 50, 3, 3, 3, 7, 79, 78, 3, 3, 23, 50, 48, 49, 53, 45, 48, 57, 45, 48, + 55, 3, 3, 3, 89, 47, 80, 73, 79, 78, 69, 69, 82, 47, 85, 83, 66, 65, 78, 76, 90, + 47, 80, 48, 50, 49, 47, 48, 48, 48, 48, 54, 68, 50, 66, 47, 65, 78, 76, 90, 48, 48, + 48, 48, 46, 68, 65, 84, 23, 50, 48, 50, 50, 45, 48, 50, 45, 48, 50, 3, 11, 72, 79, + 82, 78, 3, 19, 72, 79, 82, 78, 46, 119, 97, 118, 93, 47, 67, 111, 110, 116, 101, + 110, 116, 115, 47, 85, 110, 107, 110, 111, 119, 110, 65, 114, 116, 105, 115, 116, + 47, 85, 110, 107, 110, 111, 119, 110, 65, 108, 98, 117, 109, 47, 72, 79, 82, 78, + 46, 119, 97, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 36, 0, 128, 0, 0, 7, 12, 0, 68, 172, 0, 0, 0, 0, 0, 0, 168, 71, 105, + 0, 218, 177, 193, 12, 128, 250, 231, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 172, 0, 41, 0, 0, 0, 1, 0, 3, 0, 136, + 0, 137, 0, 138, 0, 140, 0, 142, 0, 143, 0, 144, 0, 145, 0, 148, 0, 149, 0, 150, 0, + 161, 0, 162, 0, 163, 0, 164, 0, 208, 0, 219, 0, 249, 0, 6, 1, 7, 1, 24, 1, 3, 3, 5, + 51, 5, 51, 3, 3, 3, 7, 79, 78, 3, 3, 23, 50, 48, 49, 56, 45, 48, 53, 45, 50, 53, 3, + 3, 3, 89, 47, 80, 73, 79, 78, 69, 69, 82, 47, 85, 83, 66, 65, 78, 76, 90, 47, 80, + 48, 49, 54, 47, 48, 48, 48, 48, 56, 55, 53, 69, 47, 65, 78, 76, 90, 48, 48, 48, 48, + 46, 68, 65, 84, 23, 50, 48, 50, 50, 45, 48, 50, 45, 48, 50, 61, 84, 114, 97, 99, + 107, 115, 32, 98, 121, 32, 119, 119, 119, 46, 108, 111, 111, 112, 109, 97, 115, + 116, 101, 114, 115, 46, 99, 111, 109, 27, 68, 101, 109, 111, 32, 84, 114, 97, 99, + 107, 32, 49, 3, 35, 68, 101, 109, 111, 32, 84, 114, 97, 99, 107, 32, 49, 46, 109, + 112, 51, 105, 47, 67, 111, 110, 116, 101, 110, 116, 115, 47, 76, 111, 111, 112, + 109, 97, 115, 116, 101, 114, 115, 47, 85, 110, 107, 110, 111, 119, 110, 65, 108, + 98, 117, 109, 47, 68, 101, 109, 111, 32, 84, 114, 97, 99, 107, 32, 49, 46, 109, + 112, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 160, 0, 0, 7, 12, 0, 68, 172, 0, 0, 0, 0, 0, 0, 168, 71, 105, 0, 218, 177, + 193, 12, 128, 250, 231, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 64, 1, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 172, 0, 41, 0, 0, 0, 1, 0, 3, 0, 136, 0, 137, 0, + 138, 0, 140, 0, 142, 0, 143, 0, 144, 0, 145, 0, 148, 0, 149, 0, 150, 0, 161, 0, + 162, 0, 163, 0, 164, 0, 208, 0, 219, 0, 249, 0, 6, 1, 7, 1, 24, 1, 3, 3, 5, 51, 5, + 51, 3, 3, 3, 7, 79, 78, 3, 3, 23, 50, 48, 49, 56, 45, 48, 53, 45, 50, 53, 3, 3, 3, + 89, 47, 80, 73, 79, 78, 69, 69, 82, 47, 85, 83, 66, 65, 78, 76, 90, 47, 80, 48, 49, + 54, 47, 48, 48, 48, 48, 56, 55, 53, 69, 47, 65, 78, 76, 90, 48, 48, 48, 48, 46, 68, + 65, 84, 23, 50, 48, 50, 50, 45, 48, 50, 45, 48, 50, 61, 84, 114, 97, 99, 107, 115, + 32, 98, 121, 32, 119, 119, 119, 46, 108, 111, 111, 112, 109, 97, 115, 116, 101, + 114, 115, 46, 99, 111, 109, 27, 68, 101, 109, 111, 32, 84, 114, 97, 99, 107, 32, + 49, 3, 35, 68, 101, 109, 111, 32, 84, 114, 97, 99, 107, 32, 49, 46, 109, 112, 51, + 105, 47, 67, 111, 110, 116, 101, 110, 116, 115, 47, 76, 111, 111, 112, 109, 97, + 115, 116, 101, 114, 115, 47, 85, 110, 107, 110, 111, 119, 110, 65, 108, 98, 117, + 109, 47, 68, 101, 109, 111, 32, 84, 114, 97, 99, 107, 32, 49, 46, 109, 112, 51, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 192, 0, + 0, 7, 12, 0, 68, 172, 0, 0, 0, 0, 0, 0, 246, 48, 78, 0, 59, 125, 186, 15, 128, 250, + 231, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, + 0, 0, 0, 224, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 16, 0, 128, 0, 41, 0, 0, 0, 1, 0, 3, 0, 136, 0, 137, 0, 138, 0, 140, 0, 142, + 0, 143, 0, 144, 0, 145, 0, 148, 0, 149, 0, 150, 0, 161, 0, 162, 0, 163, 0, 164, 0, + 208, 0, 219, 0, 249, 0, 6, 1, 7, 1, 24, 1, 3, 3, 5, 51, 5, 51, 3, 3, 3, 7, 79, 78, + 3, 3, 23, 50, 48, 49, 56, 45, 48, 53, 45, 50, 53, 3, 3, 3, 89, 47, 80, 73, 79, 78, + 69, 69, 82, 47, 85, 83, 66, 65, 78, 76, 90, 47, 80, 48, 53, 51, 47, 48, 48, 48, 49, + 68, 50, 49, 70, 47, 65, 78, 76, 90, 48, 48, 48, 48, 46, 68, 65, 84, 23, 50, 48, 50, + 50, 45, 48, 50, 45, 48, 50, 61, 84, 114, 97, 99, 107, 115, 32, 98, 121, 32, 119, + 119, 119, 46, 108, 111, 111, 112, 109, 97, 115, 116, 101, 114, 115, 46, 99, 111, + 109, 27, 68, 101, 109, 111, 32, 84, 114, 97, 99, 107, 32, 50, 3, 35, 68, 101, 109, + 111, 32, 84, 114, 97, 99, 107, 32, 50, 46, 109, 112, 51, 105, 47, 67, 111, 110, + 116, 101, 110, 116, 115, 47, 76, 111, 111, 112, 109, 97, 115, 116, 101, 114, 115, + 47, 85, 110, 107, 110, 111, 119, 110, 65, 108, 98, 117, 109, 47, 68, 101, 109, 111, + 32, 84, 114, 97, 99, 107, 32, 50, 46, 109, 112, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 76, 8, 204, 6, 76, 5, 252, 3, 172, 2, 80, 1, 0, 0, 96, 0, 64, 0, + ], + page, + (page_size,), + (page_size,), + ); + } }