Microkernel based hobby OS

Now it can mount a drive

+268 -63
aethelos.iso

This is a binary file and will not be displayed.

+241 -41
heartwood/src/drivers/ata.rs
··· 58 58 } 59 59 60 60 /// Detect and initialize primary master drive 61 + /// Based on r3 kernel's ATA driver: https://github.com/Narasimha1997/r3 61 62 pub fn detect_primary_master() -> Option<Self> { 62 63 let bus = ATA_PRIMARY_BASE; 63 64 let drive = 0; 64 65 65 - // Aggressive detection: just assume drive exists and try to use it 66 - // If sector reads work, it's a real drive! 67 - // This avoids IDENTIFY command which was hanging 68 - Some(AtaDrive { 69 - bus, 70 - drive, 71 - sectors: 204800, // Assume 100MB (will be corrected if FAT32 mount works) 72 - sector_size: 512, 73 - }) 66 + unsafe { 67 + // Serial marker: 'A' = Starting detection 68 + Self::debug_char(b'A'); 69 + 70 + // Step 0: Disable interrupts on ATA controller 71 + // Write to Device Control Register (0x3F6): set nIEN bit (bit 1) 72 + outb(0x3F6, 0x02); // Disable interrupts 73 + 74 + // Step 1: Select master drive 75 + outb(bus + ATA_REG_DRIVE, 0xA0); 76 + 77 + // Step 2: Wait 400ns for drive selection to settle 78 + for _ in 0..4 { 79 + inb(bus + ATA_REG_STATUS); 80 + } 81 + 82 + // Step 3: CRITICAL - Wait for BSY to clear BEFORE checking signature 83 + Self::debug_char(b'B'); // Waiting for initial BSY clear 84 + let mut timeout = 0; 85 + loop { 86 + let status = inb(bus + ATA_REG_STATUS); 87 + if (status & ATA_STATUS_BSY) == 0 { 88 + break; // BSY is clear, safe to proceed 89 + } 90 + timeout += 1; 91 + if timeout > 1000000 { 92 + Self::debug_char(b'T'); // Timeout waiting for BSY 93 + return None; 94 + } 95 + core::hint::spin_loop(); 96 + } 97 + 98 + // Step 4: Check device signature to determine ATA vs ATAPI 99 + // CRITICAL: Do this BEFORE sending any command! 100 + Self::debug_char(b'C'); // Checking signature 101 + 102 + let lba_mid = inb(bus + ATA_REG_LBA_MID); 103 + let lba_high = inb(bus + ATA_REG_LBA_HIGH); 104 + 105 + // Debug: show signature bytes 106 + Self::debug_hex(lba_mid); 107 + Self::debug_hex(lba_high); 108 + 109 + // ATAPI signature: 0x14 (LBA mid) / 0xEB (LBA high) 110 + if lba_mid == 0x14 && lba_high == 0xEB { 111 + Self::debug_char(b'P'); // ATAPI device detected 112 + return None; // We don't support ATAPI yet 113 + } 114 + 115 + // ATA signature should be 0x00 / 0x00 116 + if lba_mid != 0x00 || lba_high != 0x00 { 117 + Self::debug_char(b'U'); // Unknown signature 118 + return None; 119 + } 120 + 121 + // Step 5: Send correct IDENTIFY command (0xEC for ATA) 122 + Self::debug_char(b'D'); // Sending IDENTIFY DEVICE 123 + outb(bus + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); 124 + 125 + Self::debug_char(b'E'); // Command sent successfully! 126 + 127 + // Step 6: Wait for drive to process command (BSY to clear, then DRQ to set) 128 + Self::debug_char(b'E'); // Waiting for response 129 + timeout = 0; 130 + loop { 131 + let status = inb(bus + ATA_REG_STATUS); 132 + 133 + // Check if status is 0 (no drive) 134 + if status == 0 { 135 + Self::debug_char(b'0'); // No drive 136 + return None; 137 + } 138 + 139 + // Check for error bit 140 + if (status & ATA_STATUS_ERR) != 0 { 141 + Self::debug_char(b'!'); // Error 142 + Self::debug_hex(status); 143 + return None; 144 + } 145 + 146 + // Check if BSY is clear AND DRQ is set (data ready) 147 + if (status & ATA_STATUS_BSY) == 0 && (status & ATA_STATUS_DRQ) != 0 { 148 + Self::debug_char(b'F'); // Data ready! 149 + break; 150 + } 151 + 152 + timeout += 1; 153 + if timeout > 1000000 { 154 + Self::debug_char(b'T'); // Timeout 155 + return None; 156 + } 157 + core::hint::spin_loop(); 158 + } 159 + 160 + // Check if this is an ATA drive (not ATAPI) 161 + let lba_mid = inb(bus + ATA_REG_LBA_MID); 162 + let lba_high = inb(bus + ATA_REG_LBA_HIGH); 163 + if lba_mid != 0 || lba_high != 0 { 164 + Self::debug_char(b'P'); // ATAPI detected 165 + return None; 166 + } 167 + 168 + // Step 7: Read IDENTIFY data (256 words = 512 bytes) 169 + Self::debug_char(b'G'); // Reading data 170 + 171 + // Read 256 words (512 bytes) of identify data 172 + let mut identify_data: [u16; 256] = [0; 256]; 173 + for i in 0..256 { 174 + identify_data[i] = inw(bus + ATA_REG_DATA); 175 + } 176 + 177 + // Serial marker: 'H' = Parsing sector count 178 + Self::debug_char(b'H'); 179 + 180 + // Parse sector count from words 60-61 (28-bit LBA) 181 + let sectors_low = identify_data[60] as u32; 182 + let sectors_high = identify_data[61] as u32; 183 + let sectors = ((sectors_high as u64) << 16) | (sectors_low as u64); 184 + 185 + // If sector count is 0, use a default 186 + let sectors = if sectors > 0 { sectors } else { 2048 }; 187 + 188 + // Serial marker: 'Z' = Success! 189 + Self::debug_char(b'Z'); 190 + 191 + Some(AtaDrive { 192 + bus, 193 + drive, 194 + sectors, 195 + sector_size: 512, 196 + }) 197 + } 198 + } 199 + 200 + /// Write a debug string to COM1 serial port 201 + fn debug_str(s: &[u8]) { 202 + unsafe { 203 + for &byte in s { 204 + while (inb(0x3FD) & 0x20) == 0 {} 205 + outb(0x3F8, byte); 206 + } 207 + } 208 + } 209 + 210 + /// Write a debug character to COM1 serial port with compact prefix 211 + fn debug_char(c: u8) { 212 + // Use compact format: "*X " - write directly without waiting 213 + // to avoid potential conflicts with ATA port access 214 + unsafe { 215 + outb(0x3F8, b'*'); 216 + outb(0x3F8, c); 217 + outb(0x3F8, b' '); 218 + } 219 + } 220 + 221 + /// Write a byte as two hex digits to serial port 222 + fn debug_hex(value: u8) { 223 + const HEX: &[u8] = b"0123456789ABCDEF"; 224 + unsafe { 225 + let high = (value >> 4) & 0x0F; 226 + let low = value & 0x0F; 227 + 228 + // Write directly without waiting 229 + outb(0x3F8, b'='); 230 + outb(0x3F8, b'0'); 231 + outb(0x3F8, b'x'); 232 + outb(0x3F8, HEX[high as usize]); 233 + outb(0x3F8, HEX[low as usize]); 234 + } 74 235 } 75 236 76 237 /// Send IDENTIFY command to drive ··· 172 333 } 173 334 174 335 /// Read a single sector (28-bit LBA) 336 + /// Read a single sector using PIO mode 337 + /// Based on r3 kernel's read_sectors_lba28() 175 338 fn read_sector_pio(&self, lba: u64) -> Result<Vec<u8>, BlockDeviceError> { 176 339 if lba >= self.sectors { 177 340 return Err(BlockDeviceError::InvalidSector); 178 341 } 179 342 180 - // Select drive (LBA mode) 181 - let drive_byte = 0xE0 | (self.drive << 4) | ((lba >> 24) & 0x0F) as u8; 182 - outb(self.bus + ATA_REG_DRIVE, drive_byte); 183 - Self::wait_400ns(self.bus); 343 + unsafe { 344 + // Wait for drive to not be busy 345 + let mut timeout = 0; 346 + loop { 347 + let status = inb(self.bus + ATA_REG_STATUS); 348 + if status & ATA_STATUS_BSY == 0 { 349 + break; 350 + } 351 + timeout += 1; 352 + if timeout > 1000000 { 353 + return Err(BlockDeviceError::IoError); 354 + } 355 + } 356 + 357 + // Select drive (LBA mode) + high 4 bits of LBA 358 + let drive_byte = 0xE0 | (self.drive << 4) | ((lba >> 24) & 0x0F) as u8; 359 + outb(self.bus + ATA_REG_DRIVE, drive_byte); 184 360 185 - // Send sector count (1 sector) 186 - outb(self.bus + ATA_REG_SECTOR_COUNT, 1); 361 + // Wait 400ns 362 + for _ in 0..4 { 363 + inb(self.bus + ATA_REG_STATUS); 364 + } 365 + 366 + // Send sector count (1 sector) 367 + outb(self.bus + ATA_REG_SECTOR_COUNT, 1); 368 + 369 + // Send LBA (lower 24 bits) 370 + outb(self.bus + ATA_REG_LBA_LOW, (lba & 0xFF) as u8); 371 + outb(self.bus + ATA_REG_LBA_MID, ((lba >> 8) & 0xFF) as u8); 372 + outb(self.bus + ATA_REG_LBA_HIGH, ((lba >> 16) & 0xFF) as u8); 187 373 188 - // Send LBA 189 - outb(self.bus + ATA_REG_LBA_LOW, (lba & 0xFF) as u8); 190 - outb(self.bus + ATA_REG_LBA_MID, ((lba >> 8) & 0xFF) as u8); 191 - outb(self.bus + ATA_REG_LBA_HIGH, ((lba >> 16) & 0xFF) as u8); 374 + // Send READ SECTORS command (0x20) 375 + outb(self.bus + ATA_REG_COMMAND, ATA_CMD_READ_SECTORS); 192 376 193 - // Send READ SECTORS command 194 - outb(self.bus + ATA_REG_COMMAND, ATA_CMD_READ_SECTORS); 377 + // Wait for BSY to clear 378 + timeout = 0; 379 + loop { 380 + let status = inb(self.bus + ATA_REG_STATUS); 381 + if status & ATA_STATUS_BSY == 0 { 382 + break; 383 + } 384 + timeout += 1; 385 + if timeout > 1000000 { 386 + return Err(BlockDeviceError::IoError); 387 + } 388 + } 195 389 196 - // Wait for drive to be ready 197 - if !Self::wait_not_busy(self.bus) { 198 - return Err(BlockDeviceError::IoError); 199 - } 390 + // Wait for DRQ to be set 391 + timeout = 0; 392 + loop { 393 + let status = inb(self.bus + ATA_REG_STATUS); 394 + if status & ATA_STATUS_ERR != 0 { 395 + return Err(BlockDeviceError::IoError); 396 + } 397 + if status & ATA_STATUS_DRQ != 0 { 398 + break; 399 + } 400 + timeout += 1; 401 + if timeout > 1000000 { 402 + return Err(BlockDeviceError::IoError); 403 + } 404 + } 200 405 201 - // Wait for DRQ (with timeout) 202 - for _ in 0..1000 { 203 - let status = inb(self.bus + ATA_REG_STATUS); 204 - if status & ATA_STATUS_ERR != 0 { 205 - return Err(BlockDeviceError::IoError); 406 + // Read 256 words (512 bytes) into fixed-size array 407 + let mut data: [u16; 256] = [0; 256]; 408 + for i in 0..256 { 409 + data[i] = inw(self.bus + ATA_REG_DATA); 206 410 } 207 - if status & ATA_STATUS_DRQ != 0 { 208 - break; 411 + 412 + // Convert to Vec<u8> 413 + let mut buffer = Vec::with_capacity(512); 414 + for word in data.iter() { 415 + buffer.push((word & 0xFF) as u8); 416 + buffer.push((word >> 8) as u8); 209 417 } 210 - } 211 418 212 - // Read 512 bytes (256 words) 213 - let mut buffer = Vec::with_capacity(512); 214 - for _ in 0..256 { 215 - let word = inw(self.bus + ATA_REG_DATA); 216 - buffer.push((word & 0xFF) as u8); 217 - buffer.push((word >> 8) as u8); 419 + Ok(buffer) 218 420 } 219 - 220 - Ok(buffer) 221 421 } 222 422 223 423 /// Wait for drive to not be busy (with timeout)
+27 -21
heartwood/src/main.rs
··· 108 108 } 109 109 } 110 110 111 - /// Mount storage - using RAM disk since ATA driver has issues 111 + /// Detect ATA drives and mount FAT32 filesystem 112 112 fn detect_and_mount_storage() { 113 - use heartwood::vfs::mock_fat32::MockFat32Device; 113 + use heartwood::drivers::AtaDrive; 114 114 use heartwood::vfs::fat32::Fat32; 115 115 use heartwood::vfs::global as vfs_global; 116 116 use alloc::boxed::Box; ··· 118 118 // Initialize global VFS 119 119 vfs_global::init(); 120 120 121 - println!(" ◈ Creating RAM disk (64KB FAT32 filesystem)..."); 122 - 123 - // Create in-memory FAT32 filesystem 124 - let device = Box::new(MockFat32Device::new()); 121 + // Try to detect primary master ATA drive 122 + match AtaDrive::detect_primary_master() { 123 + Some(drive) => { 124 + let sectors = drive.sector_count(); 125 + let size_mb = (sectors * 512) / (1024 * 1024); 126 + println!(" ✓ Detected ATA drive: {} sectors (~{} MB)", sectors, size_mb); 125 127 126 - match Fat32::new(device) { 127 - Ok(fs) => { 128 - println!(" ✓ RAM disk created and mounted!"); 128 + // Try to mount as FAT32 129 + println!(" ◈ Attempting to mount FAT32 filesystem..."); 130 + match Fat32::new(Box::new(drive)) { 131 + Ok(fs) => { 132 + println!(" ✓ FAT32 filesystem mounted successfully!"); 129 133 130 - // Mount globally 131 - vfs_global::mount(Box::new(fs)); 132 - println!(" ✓ Filesystem accessible (vfs-ls, vfs-cat)"); 133 - println!(); 134 - println!(" Files available:"); 135 - println!(" /README.TXT - Welcome message"); 136 - println!(" /TEST.TXT - Test file"); 134 + // Mount globally so shell commands can access it 135 + vfs_global::mount(Box::new(fs)); 136 + println!(" ✓ Filesystem mounted at / (accessible via shell)"); 137 + println!(); 138 + println!(" Try: vfs-ls / to list files"); 139 + } 140 + Err(e) => { 141 + println!(" ✗ Failed to mount FAT32: {}", e); 142 + println!(" (Drive may not be FAT32 formatted)"); 143 + } 144 + } 137 145 } 138 - Err(e) => { 139 - println!(" ✗ Failed to create RAM disk: {}", e); 146 + None => { 147 + println!(" ⚠ No ATA drive detected"); 148 + println!(" (Use QEMU with -hda <disk.img> to attach a disk)"); 140 149 } 141 150 } 142 - 143 - println!(); 144 - println!(" Note: ATA driver postponed - RAM disk used instead"); 145 151 } 146 152 147 153 /// Initialize the Heartwood's core systems
isodir/boot/aethelos/heartwood.bin

This is a binary file and will not be displayed.

-1
serial.log
··· 1 - BSLSR12AB~b$%$%$%$%$%$%~VWG+@$%#E[~]D@VWG+@$%#E[~]D#VWG+@$%#E[~]DCVWG+@$%#E[~]DMNabcdeOPQRSDVWG+@$%#E[~]DEVWG+@$%#E[~]Dnxsu!FVWG+@$%#E[~]DGVWG+@$%#E[~]D1AabcdefghijklmBCDy3VWG+@$%#E[~]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DMmMmVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DMmMmVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DMmMmVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#E[~]DHVWG+@$%#E[~]DIVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DM...mM....mM....mM....mM....mVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~^]DJVWG+@$%#E[~^]DLVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmM........mMmM........mM........mM........mMVWG+@$%#E[~^]DNVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmM....mM....mMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DOKVWG+@$%#E[~^]DVWG+@$%#E[~^]D3HXY!SI.P12345LCKVWG+@$%#E[~^]DP12345LCT+VWG+@$%#E[~^]D*VWG+@$%#E[~^]D1VWG+@$%#E[~^]D2VWG+@$%#E[~^]D3VWG+@$%#E[~^]D4VWG+@$%#E[~^]D5VWG+@$%#E[~^]D6VWG+@$%#E[~^]D7VWG+@$%#E[~^]D8VWG+@$%#E[~^]D9VWG+@$%#E[~^]D0VWG+@$%#E[~^]D!stmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~^]DaVWG+@$%#MmMmMmMmMmMmMmMmMmMmMmMm@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~^]DbVWG+@$%#@$%#@$%#E[~^]DcVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~^]DdVWG+@$%#@$%#@$%#E[~^]DeVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P1Mm2345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P1Mm2345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P1Mm2345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P1Mm2345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P1M.m2345LCR6VWG+@$%#E[~]DP12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#@$%#@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!VWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!VWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCVWG+@$%#E[~]DR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~]DVWG+@$%#@$%#@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6MmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#@$%#@$%#E[~]DVWG+@$%#E[~]DMmMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#@$%#@$%#E[~]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6MmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DMmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DMmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!VWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!VWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6MmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DMmVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmM....mM....mMmMmMmMmMmMmMmMmMmMmVWG+@$%#E[~^]DMmMmMmMmMmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#E[~^]DVWG+@$%#@$%#@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6