![]() |
What is inside hard disk? First disks had a simple
design. They had one or more rotating platters and a moving arm with
read/write heads attached to it - one head on each side of the platter.
The arm could move and stop at the certain number of positions. When it
stopped each head could read or write data on the underlying track.
Every read or write had to be done in blocks of bytes, called sectors.
Sectors were usually 512 bytes long and there were fixed number of
sectors on each track. The drives themself didn't have much electronics and had to be controlled by CPU for every single step. First CPU had to issue command to position the arm. Then it had to instruct the drive which head should perform read and from which sector. After that CPU waited until the desired sector was moving under the head and started data transfer. This design was relatively simple and inexpensive. But there were several disadvantages. First of all, each Input/Output operation involved a lot of CPU attention and, also, the disk surface was used inefficiently. It was convenient for the programmers to have fixed number of sectors on each track, but it was a waste of space, because the longer outer tracks could hold much more data than the shorter inner ones. Later, when digital electronics became cheap, hardware engineers could resolve this problem. When IDE (Integrated Drive Electronics) disks came out they had a little processor on each drive. This helped to free up CPU time by implementing more sophisticated set of commands. The disk space was also used more efficiently. Engineers had placed more sectors on the outer tracks, but still provided software writers with a convenient "cubical" look of the disk by doing internal translation of CHS (cylinders, heads, sectors). For example my old 340M disk has only two platters = 4 heads (sides), but it reports 665 cylinders, 16 heads (sides), and 63 sectors. In reality it, probably, has more then 4*63 sectors on each outer track and a little less than 4*63 on the most inner tracks, but we could never know for sure. With the IDE disks CPU only has to tell the CHS of the sector that it wants to read and drive's electronics will position the heads and call back the CPU when it is ready to start data transfer. The newest drives have even simpler interface. Instead of addressing sectors by their CHS (cylinder, head, sector) address they use LBA (Logical Block Addressing) mode. In LBA mode a program has to tell only number of the sector from the beginning of the disk (all sectors on disk are numbered 0, 1, 2, 3, ... ). In addition to that new disks have internal buffers, where they can store many sectors. This can speed up disk access a lot, because they could read data in buffer using all four heads at the same time. Virtually all modern operating systems use LBA addressing, but the CHS notation is still around. First of all, MS-DOS, which is almost 20 years old, uses only CHS. Also some programs, like Partition Magic, would not work if partitions do not start at the cylinder or side boundary. And finally, it is easier to talk about hundreeds of cylinders than about millions of sectors. Therefore we will be using CHS notation throughout this discussion. There are several things that you have to know about CHS addressing. Suppose that we have a 340M disk with 665 cylinders, 16 heads, and 63 sectors per track. Then the legal values for cylinder numbers are 0..664, for head (side) numbers are 0..15, and for sector - 1..63. The maximum allowable values for CHS addressing mode are 0..1023, 0..255, 1..63 for cylinders, heads, and sectors respectively. If you multiply these values you will see that the largest hard disk that could be addressed with CHS is 8G. Therefore, if your disk is 12G many programs will see only 8G, because they use CHS.
How disks are partitioned? All hard disks on all IBM
compatible computers have the same way of partitioning. First sector of
the disk, called MBR (Master Boot Record), which we will be discussing
in details later, contains partition table. This table has four records,
each of them can describe one partition. In the simplest case we would
have all disk space assigned to one partition, like in the following
example: Note that MBR occupies one sector at cylinder 0, side 0, sector 1 and partition starts on the cylinder 0, side 1, sector 1. The 62 sector gap between them was left unused, because we want all partitions to start at the cylinder boundary or, at least, on the side boundary. This is not required with LBA, but we need to follow this rule in order to make happy old software (MS-DOS for example). Another important point that I want to make is that Operating System and File System are different things, which many people use interchangeably. Operating System is a piece of software which controls CPU and lets different application programs to run on the computer and use different system resources. The File System is a way to organize files and directories on the hard disk. The confusion comes because every decent operating system has one or more of its own file systems and they become clousely associated. In our example all we know is that we have FAT-16 file system. And we have no idea which operating system is installed on it. It could be MS-DOS 6.22, it could be Windows 95 or NT, or it could be all three of them installed in the different directories in the same partition. If we put additional efforts we could even install there Linux, but it is usually better to have different operating systems installed in separate partitions. Another reason to have multiple partitions is the security against computer crushes. For example, if the system crushes in such a way that FAT tables get corrupted you will lose access to all your files, because FAT table tells where each file is located on the disk. The FAT table is so important that they decided to keep two copies of FAT table at the beginning of the disk. But in case if you have very valuable files, it, might be wise to create second partition (then it will have its own FATs) and keep copies of important files there. However, do not rush to create the second partition. First of all, experience shows that 99% of errors damage only one copy of FAT and, secondly, for the majority of users it would be sufficient to copy their personal work to the floppy once a week and keep it in the safe place. So, in the case of a crash, they would only have to reformat the disk and reinstall all programs. Now, regardless of the reason, let's see what happens if we have multiple partitions. In the second example we
have two partitions with the FAT-16 file system. For some reason makers
of DOS decided that if you want to have second or third FAT partition
you have to put them not in MBR but into the Extended DOS partition.
Extended partition appears like an ordinary partition in MBR (it
occupies space) and inside it has a table similar to partition table in
MBR, called EMBR (Extended MBR), which lists partititions enclosed in
the extended partition. Inside of extended partition you can have one
more FAT partition and the reference to the next extended partition,
then another FAT, and so forth, as long as you have drive letters for
them (D:, E:, F:, ... ). All those partitions have special name: logical
drives, on contrary to the first FAT partition C:, listed in MBR,
which is primary partition. We can only speculate about the reasons for choosing such design, but there are two very obvious ones. First one is that partition table has only four records and you couldn't have more than four partitions if you didn't have extended partitions. To understand the second reason you have to know that, according to Microsoft, you can have only one primary partition on the disk and you cannot boot from the logical drives, which means that you cannot have more than one DOS-like operating system on the computer, which is another way to cut off the competitors. In fact, you can have more than one primary FAT partition and we will show later how to do that. Also note that FAT tables
in the second partition are smaller than in the first one. It obviously
happens because the second partition is smaller. The FAT tables has one
entry for each cluster in the partition - it contains number of the next
cluster in the chain. There is one chain of clusters for each file.
Number of the first cluster of the file is stored in the directory entry
for that file, along with file size, attributes, and last modification
date. Space for the directories other than root is allocated among the
data clusters, just as if they were ordinary files. Only root directory
has special location. The name of the file system is FAT-16 because it has FAT (File Allocation Table) and also because each entry in FAT is 16-bits long (2 bytes). This means that FAT-16 partition cannot have more than 65,535 clusters (2^16 = 65,536). Similarly FAT-32 has 32-bit entries and could address up to 2^32 clusters. (Actually they use only 28 bits). Based on that we can calculatete maximum partition sizes for FAT file systems. Here is the table:
The next example shows
coexistance of DOS and Linux on the same disk and some more insights on
the structure of the extended partition. Beginners can skip it and go to
the next section. First of all, this configuration could be derived from Example 2 if I we shrink both FAT partitions and then install Linux. Also you probably noticed that Linux native file system uses different way of organizing files than does FAT file system. The main structure is called i-node table. There is one i-node allocated for each file. The i-node keeps file size, attributes and file creation, last modification, and last access times. Unlike FAT file system directories have only file names and i-node numbers. The space allocation also differs from FAT, but it is out of the scope of our discussion. If you study carefully cylinder numbers in the third example you will see that extended partition has three EMBR tables each one is stored at the beginning of the extended partition and keeps a record about FAT (or other) partition and the pointer to the next extended partition. Note that first extended partition encloses all FAT and extended partitions, but all other extended partitions (level 2, 3, ... ) enclose only one data partitions. And finally I want to say, that even though this was the real partitioning scheme on my hard disk it has some drawbacks. First of all, Linux swap partition is located at the end of the disk, far from the Linux root partition. It turned out that disk heads kept going long way back and forth all the time, decreasing system performance. It is much better to place swap partition as close as possible to the partition where the OS is installed. Also some people think that if they put Windows swap file into the separate partition computer will work faster. This is true only if that partition is located on the separate hard drive, which is faster or as fast as the first one. Placing swap file on the old slow drive will not do any good. It is much better to set in the Control Panels fixed size for the swap file equal to the amount of RAM and place it on C:. Then you can run Norton Speed Disk which will optimize swap file.
The Master Boot RecordIntroductionAt the early ages of the PC, the capacity of hard disks didn't exceed 10 Mb. As a result, the FAT filesystem didn't support disks with more than 32 Mb. However, the capacity of hard disks quickly increased and operating system manufacturers had to find a way to manage these disks. The idea was to divide a disk of more than 32 Mb into smaller parts. This is called partitioning and each part of a partitioned disk is called a partition.The latest versions of the FAT filesystem can handle much larger disks, and new and more sophisticated filesystems have been created. However, in some cases partitioning is still needed. One of these cases is when several operating systems have to share one hard disks. On the other hand, some people don't like to have such large disks and prefer to divide them in smaller parts just for convenience. This page explains how the system maintains the information about the partitions of a hard disk. The Master Boot RecordThe master boot record is the sector where all the partition information is stored. The system needs to know where this sector is so it was given a fixed location : the first sector of the hard disk (head 0, cylinder 0, sector 1). Before looking at the structure of the master boot record, I'll say a word about the booting of an operating system.At startup, the BIOS of the PC loads the first sector of the first hard disk into memory (we suppose that no floppy disk is present). You can get details on this at Boot sequence of a PC. In our case the sector that will be loaded will thus be the master boot record. To identify the sector as bootable, the last word of the sector must be AA55h. This implies that, if the hard disk is the first one, the first bytes of the master boot record have to be instructions. Notice that the BIOS itself has no idea of what a partition is, it only loads the first sector of the disk into memory and executes it. Here is the structure of the master boot record.
The structure of the partition table will be explained in the next section. For the moment, we will focus on the partition code. One of the partitions holds the operating system we want to launch. This partition is called the active partition. Only one active partition can be defined at any moment. It's the partition table which stores the information about the active partition. If more than one partition is active the partition table is considered invalid. It's the job of the partition code to identify the active partition, to load the boot sector of this partition into memory and then to execute it. This sector must also be loaded at address 0000h:7C00h, so the partition code moves itself elsewhere before loading the boot sector. The partition tableThis table lies at offset +1BEh of the master boot record. It has four entries of 16 bytes each. The structure of the partition table is as follows :
Appendix A : Type of partitions
Example of partition tablesPartition table of a 850 Mbyte hard disk with a DOS partitionThe disk we analyze here is a 850 Mbyte hard disk in LBA mode with 827 cylinders, 63 sectors and 32 heads.This is the code found at addresses 1BEh to 1FEh of the Master Boot Record. It's the partition table.
As we see only the first entry of the table is used. The content of address 1BEh is 80h, meaning that this is the boot partition. The next byte (address 1BFh) is the head where the partition starts. This partition starts at head 1. The bytes at addresses 1C0h and 1C1h are used to know the sector and the cylinder where the partition starts. The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the thwo most significant bits of the cylinder number and must be appended to the value in 1C1h. This gives : 0000000000b. From all the fields above, we know the partition starts at sector 1, head 1, cylinder 0. The byte at address 1C2h is the type of partition. Here we have a DOS 4.0 with more than 32 Mbyte partition (value 06h). The next byte (address 1C3h) is the head where the partitions ends : head 1Fh or 31 (remember this is a disk with 32 heads, head 31 is thus the last). The bytes at addresses 1C4h and 1C5h are used to know the sector and the cylinder where the partition ends. The value of the first byte is FFh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the thwo most significant bits of the cylinder number and must be appended to the value in 1C5h. This gives : 1100111001b (825). From all the fields above, we know the partition ends at sector 63, head 31, cylinder 825. The bytes at addresses 1C6h to 1C9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 0000003Fh (remember that Intel architecture uses the Little-Endian format) or 63. The distance from the beginning of the partition sector to the beginning of the partition is 63 sectors since the partition begins at head 1, cylinder 0, sector 0 and there are 63 sectors per track. The bytes at addresses 1CAh to 1CDh are the number of sectors in the partition. Here we have : 00196881h or 1665153. If we multiply this number by the number of bytes in a sector (512), we get 852,558,336 bytes. This is the result expected because the partition covers all the disk space. Partition table of a 3.2 Gbyte hard disk with a Linux partitionThe disk we analyze here is a 3.2 Gbyte hard disk in LBA mode with 63 sectors/track and 128 heads/cylinder. It has two partitions : a Linux swap partition of 100 Mb and a Linux native partition of 1.5 Gb. About half of the disk is thus unused.This is the code found at addresses 1BEh to 1FEh of the Master Boot Record. It's the partition table.
As we see only the first and second entries of the table are used. The content of address 1BEh is 00h, so this isn't the boot partition (in fact, it's a Linux swap partition). The next byte (address 1BFh) is the head where the partition starts. This partition starts at head 1. The bytes at addresses 1C0h and 1C1h are used to know the sector and the cylinder where the partition starts. The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the thwo most significant bits of the cylinder number and must be appended to the value in 1C1h. This gives : 0000000000b. From all the fields above, we know the partition starts at sector 1, head 1, cylinder 0. The byte at address 1C2h is the type of partition. Here we have a Linux swap partition (value 82h). The next byte (address 1C3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last). The bytes at addresses 1C4h and 1C5h are used to know the sector and the cylinder where the partition ends. The value of the first byte is 3Fh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C5h. This gives : 0000011001b (25). From all the fields above, we know the partition ends at sector 63, head 127, cylinder 25. The bytes at addresses 1C6h to 1C9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 0000003Fh (remember that Intel architecture uses the Little-Endian format) or 63. The distance from the beginning of the partition sector to the beginning of the partition is 63 sectors since the partition begins at head 1, cylinder 0, sector 1 and there are 63 sectors per track. The bytes at addresses 1CAh to 1CDh are the number of sectors in the partition. Here we have : 000332C1h or 209601. If we multiply this number by the number of bytes in a sector (512), we get 107,315,712 bytes. The content of address 1CEh is 80h, this is a boot partition. The next byte (address 1CFh) is the head where the partition starts. This partition starts at head 0. The bytes at addresses 1D0h and 1D1h are used to know the sector and the cylinder where the partition starts. The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the thwo most significant bits of the cylinder number and must be appended to the value in 1D1h. This gives : 0000011010b. From all the fields above, we know the partition starts at sector 1, head 0, cylinder 26. The byte at address 1D2h is the type of partition. Here we have a Linux native partition (value 83h). The next byte (address 1D3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last). The bytes at addresses 1D4h and 1D5h are used to know the sector and the cylinder where the partition ends. The value of the first byte is 7Fh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1D5h. This gives : 0110010110b (406). From all the fields above, we know the partition ends at sector 63, head 127, cylinder 406. The bytes at addresses 1D6h to 1D9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 00033300h (remember that Intel architecture uses the Little-Endian format) or 209664. This is approximately the length of the first partition (107 Mb). The bytes at addresses 1DAh to 1DDh are the number of sectors in the partition. Here we have : 002EE180h or 3075384. If we multiply this number by the number of bytes in a sector (512), we get 1,573,060,608 bytes. Partition table of a 2.5 Gbyte hard disk with two DOS partitionsThe disk we analyze here is a 2.5 Gbyte hard disk in LBA mode with 620 cylinders, 63 sectors/track and 128 heads/cylinder. It has two partitions : a partition of 1 Gb and a partition of 1.5 Gb.This is the code found at addresses 1BEh to 1FEh of the Master Boot Record. It's the partition table.
As we see only the first entry of the table are used. The content of address 1BEh is 00h, so this isn't a boot partition. The next byte (address 1BFh) is the head where the partition starts. This partition starts at head 0. The bytes at addresses 1C0h and 1C1h are used to know the sector and the cylinder where the partition starts. The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C1h. This gives : 0000000001b. From all the fields above, we know the partition starts at sector 1, head 0, cylinder 1. The byte at address 1C2h is the type of partition. Here we have an extended partition (05h), meaning that the first sector of this partition is a master boot record itself. The next byte (address 1C3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last). The bytes at addresses 1C4h and 1C5h are used to know the sector and the cylinder where the partition ends. The value of the first byte is BFh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C5h. This gives : 1001101010b (618). From all the fields above, we know the partition ends at sector 63, head 127, cylinder 618. The bytes at addresses 1C6h to 1C9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 00001F80h (remember that Intel architecture uses the Little-Endian format) or 8064. The distance from the beginning of the partition sector to the beginning of the partition is 8064 sectors since the partition begins at head 0, cylinder 1, sector 1. The first cylinder is unused, it holds 63*128 = 8064 sectors. The bytes at addresses 1CAh to 1CDh are the number of sectors in the partition. Here we have : 004C0B00h or 4983552. If we multiply this number by the number of bytes in a sector (512), we get 2,551,578,624 bytes. Since this is an extended partition, its first sector has also a partition table. Here is this table :
As we see only the first and second entries of the table are used. The content of address 1BEh is 00h, so this isn't a boot partition. The next byte (address 1BFh) is the head where the partition starts. This partition starts at head 1. The bytes at addresses 1C0h and 1C1h are used to know the sector and the cylinder where the partition starts. The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C1h. This gives : 0000000001b. From all the fields above, we know the partition starts at sector 1, head 1, cylinder 1. The byte at address 1C2h is the type of partition. Here we have a DOS 4.0 partition (06h). The next byte (address 1C3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last). The bytes at addresses 1C4h and 1C5h are used to know the sector and the cylinder where the partition ends. The value of the first byte is 3Fh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C5h. This gives : 0011111110b (254). From all the fields above, we know the partition ends at sector 63, head 127, cylinder 254. The bytes at addresses 1C6h to 1C9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 0000003Fh (remember that Intel architecture uses the Little-Endian format) or 63. The bytes at addresses 1CAh to 1CDh are the number of sectors in the partition. Here we have : 001F40C1h or 2048193. If we multiply this number by the number of bytes in a sector (512), we get 1,048,674,816 bytes. The content of address 1CEh is 00h, this isn't a boot partition either. The next byte (address 1CFh) is the head where the partition starts. This partition starts at head 0. The bytes at addresses 1D0h and 1D1h are used to know the sector and the cylinder where the partition starts. The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1D1h. This gives : 0011111111b (255). From all the fields above, we know the partition starts at sector 1, head 0, cylinder 255. The byte at address 1D2h is the type of partition. Here we have an extended partition (05h). The next byte (address 1D3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last). The bytes at addresses 1D4h and 1D5h are used to know the sector and the cylinder where the partition ends. The value of the first byte is BFh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1D5h. This gives : 1001101010b (618). From all the fields above, we know the partition ends at sector 63, head 127, cylinder 618. The bytes at addresses 1D6h to 1D9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 001F4100h (remember that Intel architecture uses the Little-Endian format) or 2048256. This is approximately the length of the first partition (1 Gb). The bytes at addresses 1DAh to 1DDh are the number of sectors in the partition. Here we have : 002CCA00h or 2935296. If we multiply this number by the number of bytes in a sector (512), we get 1,502,871,552 bytes. Since this is an extended partition, we look at its first sector to find the partition table :
We have here a DOS 4.0 partition of 1.5 Gb. Example of a Master Boot Code (IPL)Here's a copy of the code found a the first sector of 850 Mbyte hard drive with one DOS 4.0 partition.
00-0E : The first thing the code does, is to disable interrupts while it is initializing the segment and stack registers. After that, it reenables them. Please note that the si register is also initialized. Its initial value is 7C00h, so that it points to the boot code. 0F-18 : The boot code is copied to 0000h:0600h. The program then jumps to the next instruction but in the copy of the code. 1D : si is loaded with 07BEh. This is the location of the first entry of the partition table. Remember that this entry is at offset 1BEh of the boot sector and that this sector is now at 600h (600h + 1BEh = 7BEh). 20-33 : This code goes through the partition table and looks for a bootable partition. If it has found a boot partition, it goes to offset 35h. If it has found a partition whose first byte isn't 80h nor 00h, it goes to offset 48h. If it hasn't found a bootable partition in any of the 4 entries of the table, it triggers interrupt 18h. 35-46 : This code is executed when a bootable partition has been found. It checks if the entries that haven't been examined yet start with a null byte (indicating a non bootable partition). If anything else is found, the partition table is considered invalid and the execution continues with the code located at offset 48h. cx is loaded with the cylinder and head information. If all the other entries of the table are start with 0, the code at offset 5Dh is executed. 48 : si is loaded with 68B. This is the offset of the string "Invalid partition table". Then execution is continued with the code at 4Bh. 4B-5B : This code is used to print an error message on the screen. si has been previously loaded by the offset of the string to print. It uses interrupt 10h to do so. The last byte of the string must be equal to 0 to indicate the end of the string. When the procedure detects the end of the string it jumps to offset 5Bh, which is an infinite loop. 5D-76 : This code loads the boot sector of the active partition at address 0000h:7C00h. It tries to do so with interrupt 13h, function 2h. cx has already been loaded with the appropriate value by the procedure at offset 35h. If an error is detected, the procedure resets the drive with interrupt 13h, function 0h and retries to read the disk. It retries 5 times. After that, si is loaded with 06A3h, the offset of the "Error loading operating system" string, and the printing procedure at offset 4Bh is called. If the procedure managed to load the boot sector, the code at offset 78h is executed. 78-86 : The si register is loaded with the value 06C2h, which is the offset of string "Missing operating system". This is done in prevision of an error. The procedure checks if the newly loaded boot sector is executable. If it is, it should find a word with value AA55h at offset 7DFEh (7C00h+1FEh). If it doesn't find it, it calls the printing procedure at offset 4Bh. If everything is allright, the procedure jumps to the boot code.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||