1 2 3 Nodelist Version 7+ 4 5 Version 0, May 30 1997 6 7 Alberto Pasquale, 2:332/504@fidonet.org 8 Thomas Waldmann, 2:2474/400@fidonet.org 9 10 11 TOPIC 12 13 A new nodelist standard that remains FULLY compatible with V7 14 applications while adding new features and resolving the major 15 shortcomings of V7. 16 17 18 0. Why V7+ ? 19 ============ 20 21 V7 is a commonly adopted standard for a "nodelist database" 22 (often V7 is also called a "nodelist index", but this is only 23 half of the truth - *.NDX is the index, but *.DAT is some sort 24 of database file). 25 26 V7 uses B-tree indices for sysop names and system addresses and 27 is really FAST. 28 29 Many software uses V7 and a totally different standard maybe 30 would not get adopted by programmers. 31 32 But V7 has a great drawback: it currently does not put all 33 information that is contained in the "raw" nodelist into the V7 34 database. 35 36 So if you use V7, you do NOT have all nodelist information that 37 you maybe WANT to use (e.g. it does not support U,Txy (FSC-0062) 38 and other new flags, some characters get "lost" due to the 39 "packing" algorithm used etc.). 40 41 This drawback will be solved with V7+ - any thing that is 42 present in a raw nodelist will also be present in the V7+ 43 database - no information is lost. 44 45 V7+ also introduces a Phone Index (useful for CID lookup) and a 46 whole set of "links" that allow to move through the Fidonet 47 structure: 48 49 - Ring of "same sysop" entries 50 - Ring of "same phone" entries 51 - Pointer to "first downlink" 52 - List of "same downlink level" 53 - Full Region and Hub information 54 55 Besides V7+ introduces a semaphore method to avoid collisions 56 between applications and the compiler. 57 58 59 1. Naming Convention 60 ==================== 61 62 The base name is user specified; from here on it will be 63 referred to as <NODEX>. 64 65 Files already used by V7, that are also used by V7+: 66 67 <NODEX>.DAT The V7 / V7+ data file. 68 V7+ remains fully compatible with V7, but adds a new 69 field (8 hex digit pointer to the DTP entry) at the 70 end of the packed data. 71 72 <NODEX>.NDX Traditional B-tree address index. 73 74 <NODEX>.SDX Traditional B-tree sysop index (case insensitive). 75 For V7 compatibility, both compilers and 76 applications MUST be able to use SYSOP.NDX instead 77 of the default <NODEX>.SDX. 78 79 V7+ specific files: 80 81 <NODEX>.DTP V7+ Data file, contains complete nodelist 82 information and compiler-generated links. 83 84 <NODEX>.PDX B-tree Phone index (case insensitive), to be used 85 just as <NODEX>.SDX. 86 87 88 The application that finds <NODEX>.DTP can assume that a V7+ 89 nodelist is available. It is the user responsibility to delete 90 old files if downgrading. 91 92 A compiler in V7+ mode MUST generate all the above files by 93 default (no need to specify anything more than "Version7+" and 94 <NODEX>). 95 96 97 98 2. V7 Database File (<NODEX>.DAT) 99 ================================= 100 101 2.1. Old structure and procedure 102 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 103 104 struct _vers7 105 { 106 short Zone; // Zone number 107 short Net; // Net number 108 short Node; // Node number 109 short HubNode; // If a point, this is point number 110 word CallCost; // phone company's charge 111 word MsgFee; // Amount charged to user for a message 112 word NodeFlags; // set of flags 113 byte ModemType; // Modem type 114 byte Phone_len; // length of phone number (not packed) 115 byte Password_len; // length of password (not packed) 116 byte Bname_len; // length of system name (unpacked) 117 byte Sname_len; // length of Sysop's name (unpacked) 118 byte Cname_len; // length of City's name (unpacked) 119 byte pack_len; // total length of packed data 120 byte BaudRate; // baud rate divided by 300 121 }; 122 123 124 Accessing V7 data is currently done like this: 125 126 1. find the stuff in the index - result is the "datpos" value - 127 the offset into the <NODEX>.DAT file 128 129 2. Seek to offset <datpos> into the <NODEX>.DAT file 130 131 3. Read sizeof(struct _vers7) bytes out of the <NODEX>.DAT file 132 into a variable of type struct _vers7 133 134 4. Read the next <Phone_len> bytes out of the <NODEX>.DAT file 135 -> Phone Number 136 137 5. Read the next <Password_len> bytes out of the <NODEX>.DAT 138 file -> Password 139 140 6. Read the next <pack_len> bytes out of the <NODEX>.DAT file 141 -> some "packed" data 142 143 7. Unpack the "packed" data 144 145 8. First <Bname_len> bytes of the unpacked data contain the 146 System's (BBS') name 147 148 9. Next <Sname_len> bytes of the unpacked data contain the 149 Sysop's name 150 151 10. Next <Cname_len> bytes of the unpacked data contain the 152 City's name 153 154 155 Data layout in the <NODEX>.DAT file is like that: 156 157 <_vers7 struct> 158 <Not packed: Phone> 159 <Not packed: Password> 160 <Packed: <BBS name> 161 <Sysop name> 162 <City name> 163 > 164 165 166 2.2. New structure and procedure 167 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 168 169 struct _vers7 is NOT changed: both indexed and sequential 170 accesses are guaranteed compatible with V7. 171 172 There's only a slight addition in the packed data, see below. 173 174 Accessing V7/V7+ data should be done like this: 175 176 1. | 177 ... | 178 10. | all the same as described in section 2.1 (compatibility!) 179 180 11. Check if there are 8 hex digits at the end of the packed 181 data, after <Bname_len>+<Sname_len>+<Cname_len> bytes (see 182 steps 7..10). 183 184 In a V7+ nodelist, you should _always_ find these 8 hex 185 digits at the end of the packed data, BUT a V7 nodelist 186 editor may have removed them from modified entries. 187 188 Applications MUST be able to handle the "missing 8 hex 189 digits" situation as a normal condition and proceed as 190 possible with the simple V7 data (some message signalling 191 the situation may be issued, abnormal termination is 192 unacceptable behaviour). 193 194 If the 8 hex digits are found, they represent an offset into 195 the new <NODEX>.DTP file. 196 197 Applications MUST ignore any data possibly following the 8 198 hex digit pointer. 199 200 Due to the V7 base-40 3:2 packing algorithm, the compilers 201 have to pad the data to be compressed so that its length is 202 a multiple of 3: it is recommended that the space (ASCII 203 0x20) is used. 204 205 206 12. Seek into <NODEX>.DTP to the offset you got in step 11. 207 208 13. Read/Process <NODEX>.DTP fields as described in section 3. 209 210 211 So the new data layout in the <NODEX>.DAT file is like that: 212 213 <_vers7 struct> 214 <Not packed: Phone> 215 <Not packed: Password> 216 <Packed: <BBS name> 217 <Sysop name> 218 <City name> 219 <8-hex-digit-offset into <NODEX>.DTP> 220 > 221 222 223 3. <NODEX>.DTP file layout 224 ========================== 225 226 Let's define some glossary: 227 228 byte 8 bit unsigned integer 229 word 16 bit unsigned integer (LSB first) 230 dword 32 bit unsigned integer (LSB first) 231 232 233 The <NODEX>.DTP file has the following layout: 234 235 <Header> File header 236 <Entry> Entry for first compiled system 237 <Entry> Entry for second compiled system 238 <Entry> Entry for third compiled system 239 ... 240 241 242 3.1. <Header> 243 ~~~~~~~~~~~~~ 244 245 <Header> has the following layout: 246 247 <Control> Miscellaneous Information for Compatibility 248 <TopLink> Link to top level fidonet hierarchy 249 250 251 3.1.1. <Control> Structure 252 ~~~~~~~~~~~~~~~~~~~~~~~~~~ 253 254 struct _DTPCtl { 255 word size; // Size of this control structure 256 byte Version; // Version of DTP file 257 byte AllFixSize; // sizeof (_DTPAllLnk) 258 byte AddFixSize; // sizeof (_DTPNodeLnk) 259 }; 260 261 262 size: 263 This structure may be expanded in the future, so size is 264 provided to allow compatible positioning on the following 265 <TopLink> record. 266 267 Version: 268 This is the V7+ Version, currently 0. 269 The compatibility towards previous versions is guaranteed, 270 so correctly behaved applications will have no problems 271 dealing with newer versions of V7+. 272 273 When new features will be added, new applications will be 274 able to check for the version level of the V7+ database, 275 while old ones will remain compatible. 276 277 The check will be "if Version >= n then ...". 278 279 AllFixSize: 280 This is the size of the fixed-length structure associated 281 with ANY system in the nodelist. It is provided to allow 282 compatible positioning on the following field, in the case 283 of future extensions. 284 285 AddFixSize: 286 This is the size of the fixed-length structure associated 287 with Nodes only (no points) and with <TopLink>. It is 288 provided to allow compatible positioning on the following 289 field, in the case of future extensions. 290 291 292 3.1.2. <TopLink> 293 ~~~~~~~~~~~~~~~~ 294 295 V7+ has pointers to link the entire fidonet structure, from the 296 top coordinators to the points. 297 298 The <NODEX>.DTP header contains the link to the first (in 299 zone/region/net/hub/node/point order) "top level" system found 300 in the nodelist, usually ZC1. 301 302 struct _DTPNodeLnk { 303 word ndowns; // number of systems in lower level 304 dword FlOfs; // DAT offset of "Lower Fido Level" 305 }; 306 307 308 ndowns: 309 The number of direct downlinks; in this case it is the 310 number of "top level" systems (systems that do not have 311 uplinks in the nodelist). 312 313 Usually it's the number of ZCs. 314 315 Please note that if you have included a Region segment and 316 the corresponding Zone is not included in other nodelists 317 compiled to the same <NODEX>.*, this RC will be a "Top 318 Level" system. The same happens in the case of lower level 319 systems that are "orphans" of the upper coordinator. 320 321 FlOfs: 322 Offset into <NODEX>.DAT for the first direct downlink; in 323 this case it's usually ZC1. 324 325 326 3.2. <Entry> 327 ~~~~~~~~~~~~ 328 329 This is the <NODEX>.DTP entry for each and every compiled 330 system, pointed to by the 8-hex-digit offset found at the end of 331 the _vers7 packed data. 332 333 334 The layout is: 335 336 <Links> Fixed size info (see <Header>) 337 <Raw-size> word (size of following raw-line) 338 <Raw-nodelist-line> variable size raw nodelist line 339 340 341 This layout may be expanded in the future, both in the 342 fixed-length and variable-length sections. 343 344 Please, always use the size information found in the <Header> to 345 remain compatible with future V7+ extensions. 346 347 348 3.2.1. <Links> 349 ~~~~~~~~~~~~~~ 350 351 The layout is: 352 353 <AllLinks> Common to all entries 354 [<NodeLink>] Not present for Points 355 356 357 3.2.1.1. <AllLinks> 358 ~~~~~~~~~~~~~~~~~~~ 359 360 The following structure is used for all the systems in the 361 nodelist. 362 363 364 struct _DTPAllLnk { 365 word Region; // Region 366 word Hub; // Hub 367 dword SOfs; // DAT offset of next Same SysOp entry 368 dword POfs; // DAT offset of next Same Phone entry 369 dword FeOfs; // DAT offset of next "Equal Fido Level" 370 byte Sn; // Number (base 0) of SysOp entry (ADR order) 371 byte Pn; // Number (base 0) of Phone entry (ADR order) 372 }; 373 374 375 Region: 376 Region number, 0 if none. 377 378 Hub: 379 Hub number, 0 if none. 380 381 Please note that the "NodeHub" field of _vers7 may not 382 always be the same as this one, not only because it is 383 absent for points, but also because the compiler may 384 infer the Hub from other nodelist entries while linking 385 <NODEX>.DTP. 386 387 DO NOT USE NodeHub in _vers7 for reliable Hub information. 388 389 SOfs: 390 Offset into <NODEX>.DAT for next system with the same 391 SysOp name (in order of Address). 392 393 0xffffffff if none. 394 395 This is a RING link, that is the last entry points to the 396 first one. 397 398 POfs: 399 Offset into <NODEX>.DAT for next system with the same 400 Phone number (in order of Address). 401 402 0xffffffff if none. 403 404 This is a RING link, that is the last entry points to the 405 first one. 406 407 FeOfs: 408 Offset into <NODEX>.DAT for next system at the same 409 "fidonet level", that is with the same direct 410 uplink/coordinator. 411 412 0xffffffff if none. 413 414 This is a LIST link, that is the last entry points nowhere 415 (0xffffffff). 416 417 Please note that "equal level" systems are not necessarily 418 all of the same coordination level (all HCs or RCs etc.). 419 420 For example a ZC may have as direct downlinks (linked with 421 FeOfs between one another): 422 423 - his points (usually administrative entries should not 424 have points, but it may happen), 425 426 - Independent nodes in the Zone 427 428 - Independent HCs in the Zone 429 430 - Independent NCs in the Zone 431 432 - RCs in the zone 433 434 Sn: 435 Number of same-sysop entry (0 based). 436 0xff if no link available. 437 438 Please do NOT use Sn to check for links, use SOfs instead. 439 440 Pn: 441 Number of same-phone entry (0 base). 442 0xff if no link available. 443 444 Please do NOT use Pn to check for links, use POfs instead. 445 446 447 When you are looking for a SysOp or Phone that has multiple 448 entries in the index, you get one and then you follow the links 449 (SOfs, POfs) through all the remaining entries. 450 451 Since the first entry (got from the index) may be in the middle 452 of the "Ring", you can use Sn and Pn to know how many "lower" 453 entries you will find. This may be useful for keeping the 454 "Address order" while gathering all the information throughout 455 the RING. 456 457 Please note that some "common" entries (as "-Unpublished-" for 458 the phone number), may have more than 254 links; so be aware 459 that Sn and Pn may (under exceptional conditions) overflow, 460 arrive at 0xff and restart from 0x00. 461 462 This should be no concern when doing a normal lookup, but 463 "statistical programs" that list all the Rings must be careful. 464 465 The proper way to check whether you have finished the RING is to 466 check the new SOfs/POfs against the first encountered one; Sn/Pn 467 should be used for reference only. 468 469 470 471 3.2.1.2. <NodeLink> 472 ~~~~~~~~~~~~~~~~~~~ 473 474 The following structure is absent for points, since they do not 475 have downlinks. It's the same structure used in the <Header> for 476 <TopLink>. 477 478 479 struct _DTPNodeLnk { 480 word ndowns; // number of systems in lower level 481 dword FlOfs; // DAT offset of "Lower Fido Level" 482 }; 483 484 485 ndowns: 486 The number of direct downlinks. 487 488 It includes the lower level coordinators and all the 489 systems that, for some reason, are orphans of the upper 490 coordinator (not included in compilation or not existent). 491 492 Examples: 493 494 ZCs -> ZC's points 495 independent nodes in the zone 496 independent HCs in the zone 497 independent NCs in the zone 498 RCs in the zone 499 500 RCs -> RC's points 501 independent nodes in the region 502 independent HCs in the region 503 NCs in the region 504 505 NCs -> NC's points 506 independent nodes in the net 507 HCs in the net 508 509 HCs -> HC's points 510 nodes in the Hub 511 512 Node -> Node's points 513 514 515 516 FlOfs: 517 Offset into <NODEX>.DAT for the first direct downlink, in 518 "zone/region/net/hub/node/point" order. 519 520 521 522 3.2.2. <Raw-size> 523 ~~~~~~~~~~~~~~~~~ 524 525 This is a word specifying the length of the following 526 <raw-nodelist-line> field. 527 528 529 3.2.3. <Raw-nodelist-line> 530 ~~~~~~~~~~~~~~~~~~~~~~~~~~ 531 532 This is the zero terminated raw nodelist line, taken verbatim 533 from the source nodelist; neither carriage-return nor line-feed 534 is present. 535 536 REQUIREMENTs for applications that use this field: 537 538 - The line's fields must be recognized ONLY by considering the 539 comma ',' as a separator. 540 541 - Fields containing space are to be handled normally. 542 543 - Unknown qualifiers at the start of the line (the field usued 544 for Hub, Host, Region, Zone) must be accepted. 545 546 - The second field (where the node number is usually placed) 547 may contain further information and space: it must be accepted 548 without error. 549 550 551 3.3. DTP extensions 552 ~~~~~~~~~~~~~~~~~~~ 553 554 The DTP format is suitable for backward compatible extensions. 555 556 If you would like new fields, please contact Alberto Pasquale 557 (2:332/504@fidonet) and/or Thomas Waldmann (2:2474/400@fidonet) 558 for discussion. 559 560 If the new field is considered useful, a draft for the new 561 version of V7+ will be issued by Alberto Pasquale. 562 563 564 565 4. <NODEX>.PDX Phone Index 566 ========================== 567 568 The purpose of the Phone Index is to allow an indexed search of 569 a system entry from its phone number. 570 571 This is especially useful with CID (caller ID) enabled systems. 572 573 574 4.1. <NODEX>.PDX format 575 ~~~~~~~~~~~~~~~~~~~~~~~ 576 577 The index is a btree, just like those for the Address and SysOp 578 indices that are standard in Version 7. 579 580 Phone numbers will be indexed in the "processed" dialable form 581 (i.e. as in the V7 phone field) after removal of dashes. 582 583 Special non-numerical phone entries, including IP addresses and 584 internet domains, are indexed verbatim (the possible 585 translations operated by the nodelist compiler to allow the 586 dialing on some mailers is NOT applied to the indexed entry). 587 588 The indexing is NOT case sensitive, although the case is 589 retained in the index entries. 590 591 The index look-up must be done just the same way as for the SysOp 592 index: from the "phone number" string you obtain a pointer to 593 the corresponding entry in the <NODEX>.DAT. 594 595 Please be aware that multiple entries with the same "phone" are 596 possible, e.g for administrative akas; the Phone links in 597 <NODEX>.DTP allow easy browsing of all the "same phone" entries 598 once you have got one by index. 599 600 Currently there is no purpose in doing a case sensitive lookup; 601 in the case it becomes useful in the future, the application may 602 optionally provide settings to allow that by skipping 603 non-case-matching entries. 604 605 606 4.2. The Look-up problem 607 ~~~~~~~~~~~~~~~~~~~~~~~~ 608 609 Since most ISDN devices do NOT report the CID as a "ready to 610 dial" number, some processing is required before looking up the 611 index. 612 613 Let's classify the CID reported by ISDN devices in various 614 nations into categories: 615 616 Cat A reports CID with domestic and international dialing codes, 617 local numbers have the area code. 618 619 Cat B reports CID with NO long distance dialing code, 620 local numbers have the area code. 621 622 Cat C reports CID exactly as dialable. 623 624 Cat D reports CID with NO long distance dialing code, 625 local numbers are exactly dialable. 626 627 628 629 I will now explain with an example: 630 631 I live in Modena, Italy; 632 633 Country code : 39 634 District (area) code : 59 635 domestic code : 0 636 international code : 00 637 638 639 Call Type A-CID B-CID Dialable 640 641 Local 059246112 59246112 246112 642 Domestic 0513456789 513456789 0513456789 643 International 00492312345 492312345 00492312345 644 645 646 C-CID D-CID 647 648 Local 246112 246112 649 Domestic 0513456789 513456789 650 International 00492312345 492312345 651 652 653 Processing needed: 654 655 Category A: for local calls we need to remove the domestic and 656 district codes; domestic and international calls do not need any 657 processing. 658 659 Category B: we need to attempt finding a domestic number then, 660 in case of failure, try the international one; unfortunately the 661 CID reported by these devices allows for some ambiguity. 662 663 Category C: no processing needed. 664 665 Category D: we need to attempt finding a local number, if not 666 found we look for a domestic number, if still not found we try 667 the international one. Even more ambigous than B. 668 669 670 4.3. The ALGORITHM 671 ~~~~~~~~~~~~~~~~~~ 672 673 The application must have configurable District/Area, domestic 674 and international codes; let's name them: 675 676 AreaCode 677 DomesticPrefix 678 IntlPrefix 679 680 Besides, the application must have a configurable "category", 681 which must have selections for cases A,B,C,D; let's name this 682 variable: 683 684 Category 685 686 687 Let "Search" be the name of a function that does the index 688 look-up. Please be aware that the index may contain multiple 689 entries with the same "phone" value (perhaps administrative 690 akas). 691 692 "Restore CID" means "restore the CID as got from the device". 693 694 Start: 695 696 get CID 697 698 if (category == A) { 699 If (CID begins with DomesticPrefix+AreaCode) 700 Remove DomesticPrefix and AreaCode // is local 701 Search 702 goto END 703 } 704 705 706 if (category == B) { 707 If (CID begins with AreaCode) { // local or intl 708 remove AreaCode // try local 709 Search 710 if (found) 711 goto END // is local 712 else { 713 Restore CID 714 Add IntlPrefix // try international 715 Search 716 goto END 717 } 718 } else { // domestic or intl 719 Add DomesticPrefix // try domestic 720 Search 721 if (found) 722 goto END // is domestic 723 else { 724 Restore CID // try intl 725 Add IntlPrefix 726 Search 727 goto END 728 } 729 730 } 731 } 732 733 734 if (category == C) { // no processing required 735 Search 736 goto END 737 } 738 739 if (category == D) { 740 Search // try local 741 if (found) // is local 742 goto END 743 else { 744 Add DomesticPrefix // try domestic 745 Search 746 if (found) // is domestic 747 goto END 748 else { // try international 749 Restore CID 750 Add IntlPrefix 751 Search 752 goto END 753 } 754 } 755 } 756 757 758 END: report results (pointer to NODEX.DAT or nothing found) 759 760 The Phone links in <NODEX>.DTP allow easy browsing of all 761 remaining "same phone" entries. 762 763 764 5. V7+ Semaphore 765 ================ 766 767 To avoid collisions between the nodelist compiler and V7+ 768 applications, a semaphore is used. 769 770 When the compiler needs exclusive access to the nodelist files, 771 it creates (if non existent) and keeps open in SH_DENYRW mode a 772 "<NODEX>.BSY" file. 773 774 When the application must access the nodelist files, it creates 775 (if non existent) and keeps open for reading in SH_DENYWR mode 776 the "<NODEX>.BSY" file. 777 778 This method allows for concurrent access by multiple programs in 779 "read" mode, while granting exclusive access to the compiler. 780 781 Please note that <NODEX>.BSY does NOT need to be deleted in case 782 of abnormal termination or power failure since it's considered 783 busy only while kept open. 784 785 786 Example for a program that must read V7+: 787 788 bsyname is the "<NODEX>.BSY" file name; 789 timeout is the timeout in seconds; 790 the file handle is returned on success, -1 on timeout 791 792 793 int waitopen (const char *bsyname, int timeout) // -1 on timeout 794 { 795 int ret = -1; 796 int i = 0; 797 798 do { 799 if (i > 0) 800 sleep (1); 801 if (access (bsyname, F_OK)) { // file not existent 802 int handle = open (bsyname, O_WRONLY | O_CREAT, S_IWRITE); 803 if (handle != -1) 804 close (handle); 805 } 806 ret = sopen (bsyname, O_RDONLY, SH_DENYWR); 807 i ++; 808 } while ((ret == -1) && (i < timeout) && 809 ((errno == EACCES) || (errno == ENOENT))); 810 // sharing violation or file not found 811 return ret; 812 } 813 814 815 816 6. Space/Time needed for V7+ database vs. usability 817 =================================================== 818 819 The V7+ DTP file may be considered redundant, since it contains 820 the entire "source" nodelist line, that duplicates some of the 821 information already present in the V7 DAT file. 822 823 Let's look at the time and space overhead involved and at the 824 gain in usability: 825 826 827 Time: 828 829 Accessing V7+ is as fast as V7, if you use the normal V7 access 830 method (and if you are NOT interested in the additional data). 831 832 If you access the additional data in the <NODEX>.DTP file, you 833 have 1 direct file access more. Nothing to worry about... 834 835 Generating a V7+ database will take somewhat longer since there 836 is more data to be written to disk, links to be set, indices to 837 be prepared; on modern machines this should not be a concern. 838 839 840 Space: 841 842 Space needed is about twice as much as for V7, but this should 843 be no concern on modern machines. 844 845 846 Usability: 847 848 - Full and complete (no lossy compression) nodelist information 849 850 - Phone Index for easy CID lookup 851 852 - SysOp/Phone/Fidonet links for easy nodelist browsing 853 854 - Backward compatible extendability 855 856 857 858 7. Sample "C" source code (taken from BT-XE) 859 ============================================ 860 861 See archive v7p_src.* ... 862 863 Attention: this source code is far from being final - in fact it 864 is the very first V7+ implementation in BT-XE and does 865 not support all stuff that has been defined in this 866 document. But it can read and parse V7+ data and is 867 maybe better than no source code at all ... 868 869 870 8. History of this document 871 =========================== 872 873 Draft 1->8: preliminary thoughts about possible versions of V7+. 874 875 Draft 9: completely rewritten, this should be the final 876 "Version_0" of V7+. 877 878 Version 0: first release version. 879 880 881