1<html> 2 3<head> 4<meta http-equiv="Content-Language" content="en-us"> 5<meta name="GENERATOR" content="Microsoft FrontPage 5.0"> 6<meta name="ProgId" content="FrontPage.Editor.Document"> 7<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 8<title>Filesystem Relative Proposal</title> 9<link href="styles.css" rel="stylesheet"> 10</head> 11 12<body> 13 14<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111"> 15 <tr> 16 <td width="277"> 17<a href="../../../index.htm"> 18<img src="../../../boost.png" alt="boost.png (6897 bytes)" align="middle" width="300" height="86" border="0"></a></td> 19 <td align="middle"> 20 <font size="7">Filesystem Relative<br> 21 Draft Proposal</font> 22 </td> 23 </tr> 24</table> 25 26<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" 27 bordercolor="#111111" bgcolor="#D7EEFF" width="100%"> 28 <tr> 29 <td><a href="index.htm">Home</a> 30 <a href="tutorial.html">Tutorial</a> 31 <a href="reference.html">Reference</a> 32 <a href="faq.htm">FAQ</a> 33 <a href="release_history.html">Releases</a> 34 <a href="portability_guide.htm">Portability</a> 35 <a href="v3.html">V3 Intro</a> 36 <a href="v3_design.html">V3 Design</a> 37 <a href="deprecated.html">Deprecated</a> 38 <a href="issue_reporting.html">Bug Reports </a> 39 </td> 40</table> 41 42<p><a href="#Introduction"> 43 Introduction</a><br> 44 <a href="#Acknowledgement">Acknowledgement</a><br> 45 <a href="#Preliminary-implementation">Preliminary implementation</a><br> 46<a href="#Requirements">Requirements</a><br> 47<a href="#Issues">Issues</a><br> 48<a href="#Design-decisions"> 49 Design decisions</a><br> 50 <a href="#Provide-separate-relative">Provide separate lexical and 51 operational <code>relative</code> functions</a><br> 52 <a href="#Provide-separate-proximate">Provide 53separate lexical and operational <code>proximate</code> functions</a><br> 54 <a href="#Add-lexical-functions">Add lexical functions as <code>path</code> member functions</a><br> 55 <a href="#Provide-normal">Provide a non-member function 56<code>lexically_normal</code> returning a 57 normal form path</a><br> 58 <a href="#Provide-weakly">Provide a <code>weakly_canonical</code> operational function</a><br> 59 <a href="#just-work">Resolve issues in ways that "just work" for users</a><br> 60 <a href="#mismatch">Specify <code>lexical relative</code> in terms 61 of <code>std::mismatch</code></a><br> 62 <a href="#Specify-op-rel-weakly">Specify operational <code>relative</code> in terms of <code> 63 weakly_canonical</code></a><br> 64 <a href="#Specify-op-rel-lex-rel">Specify operational <code>relative</code> in terms of 65 <code>lexically 66 relative</code></a><br> 67<a href="#Proposed-wording">Proposed wording</a><br> 68 <a href="#Define-normal-form">Define <i>normal form</i></a><br> 69 <a href="#New-class-path-member-functions">New class path member functions</a><br> 70 <a href="#Synopsis-path">Synopsis</a><br> 71 <a href="#Specification-path">Specification</a><br> 72 <a href="#operational-functions">New operational functions</a><br> 73 <a href="#Synopsis-ops">Synopsis</a><br> 74 <a href="#Specification-ops">Specification</a></p> 75 76<h2> 77 <a name="Introduction">Introduction</a></h2> 78 79<p>There have been requests for a Filesystem library relative function for at 80 least ten years.</p> 81 82<p> 83 The requested functionality seems simple - given two paths with a common 84 prefix, return the non-common suffix portion of one of the paths such that 85 it is relative to the other path.</p> 86 87<p> 88 In terms of the Filesystem library,</p> 89 90<blockquote> 91 <pre>path p("/a/b/c"); 92path base("/a/b"); 93path rel = relative(p, base); // the requested function 94cout << rel << endl; // outputs "c" 95assert(absolute(rel, base) == p);</pre> 96</blockquote> 97<p>If that was all there was to it, the Filesystem library would have had a 98<code>relative</code> function years ago.</p> 99<blockquote> 100<p>Blocking issues: Clashing requirements, symlinks, directory placeholders (<i>dot</i>, 101<i>dot-dot</i>), user-expectations, corner cases.</p> 102</blockquote> 103<h3><a name="Acknowledgement">Acknowledgement</a></h3> 104<p>A paper by Jamie Allsop, <i>Additions to Filesystem supporting Relative Paths</i>, 105is what broke my mental logjam. Much of what follows is based directly on 106Jamie's analysis and proposal. The <code>weakly_canonical</code> function and 107aspects of the semantic specifications are my contributions. Mistakes, of 108course, are mine.</p> 109<h3><a name="Preliminary-implementation">Preliminary implementation</a></h3> 110<p>A preliminary implementation is available in the 111<a href="https://github.com/boostorg/filesystem/tree/feature/relative2"> 112feature/relative2</a> branch of the Boost Filesystem Git repository. See 113<a href="https://github.com/boostorg/filesystem/tree/feature/relative2"> 114github.com/boostorg/filesystem/tree/feature/relative2</a></p> 115<h2><a name="Requirements">Requirements</a></h2> 116<b><a name="Requirement-1">Requirement 1</a>:</b> Some uses require symlinks be followed; i.e. the path must be resolved in 117 the actual file system.<p><b><a name="Requirement-2">Requirement 2</a>: </b>Some uses require symlinks not be followed; i.e. the path must not be 118 resolved in the actual file system.</p> 119<b><a name="Requirement-3">Requirement 3</a>: </b>Some uses require removing redundant current directory (<i>dot</i>) 120 or parent directory (<i>dot-dot</i>) placeholders.<p><b> 121<a name="Requirement-4">Requirement 4</a>: </b>Some uses do not require removing redundant current directory (<i>dot</i>) 122 or parent directory (<i>dot-dot</i>) placeholders since the path is known to 123be 124already in normal form.</p> 125<h2><a name="Issues">Issues</a></h2> 126<p><b><a name="Issue-1">Issue 1</a>:</b> What happens if <code>p</code> 127and <code>base</code> are themselves relative?</p> 128<b><a name="Issue-2">Issue 2</a>:</b> What happens if there is no common prefix? Is this an error, the whole of 129 <code>p</code> is relative to <code>base</code>, or something else?<p><b> 130<a name="Issue-3">Issue 3</a>:</b> What happens if <code>p</code>, <code>base</code>, or both are empty?</p> 131<b><a name="Issue-4">Issue 4</a>:</b> What happens if <code>p</code> and <code>base</code> are the same?<p> 132<b><a name="Issue-5">Issue 5</a>:</b> How is the "common prefix" determined?</p> 133<b><a name="Issue-6">Issue 6</a>:</b> What happens if portions of <code>p</code> or <code>base</code> exist but 134 the entire path does not exist and yet symlinks need to be followed?<p><b> 135<a name="Issue-7">Issue 7</a>:</b> What happens when a symlink in the existing portion of a path is affected 136 by a directory (<i>dot-dot</i>) placeholder in a later non-existent portion of 137 the path?</p> 138<p><b><a name="Issue-8">Issue 8</a>:</b> Overly complex semantics (and thus 139specifications) in preliminary designs made reasoning about uses difficult.</p> 140<p><b><a name="Issue-9">Issue 9</a>: </b>Some uses never have redundant current directory (<i>dot</i>) 141 or parent directory (<i>dot-dot</i>) placeholders, so a removal operation 142 would be an unnecessary expense although otherwise harmless.</p> 143 144<h2> 145 <a name="Design-decisions">Design decisions</a></h2> 146 147<h4> 148 <a name="Provide-separate-relative">Provide separate</a> lexical and 149 operational <code>relative</code> functions</h4> 150 151<p align="left"> 152 Resolves the conflict between <a href="#Requirement-1">requirement 1</a> 153 and <a href="#Requirement-2">requirement 2</a> and ensures both 154 requirements are met.</p> 155 156<p> 157 A purely lexical function is needed by users working with directory 158 hierarchies that do not actually exist.</p> 159 160<p> 161 An operational function that queries the current file system for existence 162 and follows symlinks is needed by users working with actual existing 163 directory hierarchies.</p> 164 165<h4> 166 <a name="Provide-separate-proximate">Provide separate</a> lexical and operational 167 <code>proximate</code> functions</h4> 168 169<p> 170 Although not the only possibility, a likely fallback when the relative 171 functions cannot find a relative path is to return the path being made relative. As 172 a convenience, the <code>proximate</code> functions do just that.</p> 173 174<h4> 175 <a name="Add-lexical-functions">Add lexical functions as 176 <code>path</code> member functions</a></h4> 177 178<p dir="ltr"> 179 The Filesystem library is unusual in that it has several functions with 180 both lexical (i.e. cheap) and operational (i.e. expensive due to file 181 system access) forms with differing semantics. It is important that users 182 choose the form that meets their application's specific needs. The library 183 has always made the distinction via the convention of lexical functions 184 being members of class <code>path</code>, while operational functions are 185 non-member functions. The lexical functions proposed here also use the 186 name prefix <code>lexically_</code> to drive home the distinction.</p> 187 188<p> 189 For the contrary argument, see Sutter and Alexandrescu, <i>C++ Coding Standards</i>, 44: 190 "Prefer writing nonmember nonfriend functions", and Meyers, <i>Effective C++ Third Edition</i>, 23: 191 "Prefer non-member non-friend functions to member functions."</p> 192 193<h4> 194 <a name="Provide-normal">Provide</a><b> </b>a non-member function <code> 195 <a href="#normal">lexically_normal</a></code> returning a 196 <a href="#normal-form">normal form</a> path</h4> 197 198<p> 199 Enables resolution of <a href="#Requirement-3">requirement 3</a> and 200 <a href="#Requirement-4">requirement 4</a> in a way consistent with 201 <a href="#Issue-9">issue 9</a>. Is a contributor to the resolution of 202 <a href="#Issue-8">issue 8</a>.</p> 203 204<p> 205 "Normalization" is the process of removing redundant current directory (<i>dot</i>) 206 , parent 207 directory (<i>dot-dot</i>), and directory separator elements.</p> 208 209<p> 210 Normalization is a byproduct the current <code>canonical</code> function. 211 But for the path returned by the 212 proposed <code><a href="#weakly_canonical">weakly_canonical</a></code> function, 213 only any leading canonic portion is in canonical form. So any trailing 214 portion of the returned path has not been normalized.</p> 215 216<p> 217 Jamie Allsop has proposed adding a separate normalization function returning a 218 path, and I agree with him.</p> 219 220<p> 221 Boost.filesystem has a deprecated non-const normalization function that 222 modifies the path, but I agree with Jamie that a function returning a path 223 is a better solution.</p> 224 225<h4> 226 <a name="Provide-weakly">Provide</a><b> </b>a <code><a href="#weakly_canonical">weakly_canonical</a></code> operational function</h4> 227 228<p> 229 Resolves <a href="#Issue-6">issue 6</a>, <a href="#Issue-7">issue 7</a>, 230 <a href="#Issue-9">issue 9</a>, and is a contributor to the resolution of 231 <a href="#Issue-8">issue 8</a>.</p> 232 233<p> 234 The operational function 235 <code>weakly_canonical(p)</code> returns a path composed of <code> 236 canonical(x)/y</code>, where <code>x</code> is a path composed of the 237 longest leading sequence of elements in <code>p</code> that exist, and 238 <code>y</code> is a path composed of the remaining trailing non-existent elements of 239 <code>p</code> if any. "<code>weakly</code>" refers to weakened existence 240 requirements compared to the existing canonical function.</p> 241 242<ul> 243 <li>Having <code>weakly_canonical</code> as a separate function, and then 244 specifying the processing of operational <code>relative</code> arguments in 245 terms of calls to <code>weakly_canonical</code> makes it much easier to 246 specify the operational <code>relative</code> function and reason about it. 247 The difficulty of reasoning about operational <code>relative</code> 248 semantics before the invention of <code>weakly_canonical</code> was what led to its 249 initial development.</li> 250 <li>Having <code>weakly_canonical</code> as a separate function also allows 251 use in other contexts.</li> 252 <li>Specifying the return be in <a href="#normal-form">normal form</a> is an 253 engineering trade-off to resolve <a href="#Issue-7">issue 7</a> in a way that 254 just works for most use cases.</li> 255 <li>Specifying normative encouragement to not perform unneeded normalization 256 is a reasonable resolution for <a href="#Issue-9">issue 9</a>.</li> 257</ul> 258 259<h4> 260 Resolve issues in ways that "<a name="just-work">just work</a>" for users</h4> 261 262<p> 263 Resolves issues <a href="#Issue-1">1</a>, <a href="#Issue-2">2</a>, 264 <a href="#Issue-3">3</a>, <a href="#Issue-4">4</a>, <a href="#Issue-7">6</a>, 265 and <a href="#Issue-7">7</a>. Is a contributor to the resolution of 266 <a href="#Issue-8">issue 8</a>.</p> 267 268<p> 269 The "just works" approach was suggested by Jamie Allsop. It is implemented 270 by specifying a reasonable return value for all of the "What happens 271 if..." corner case issues, rather that treating them as hard errors 272 requiring an exception or error code.</p> 273 274<h4> 275 Specify <a href="#lex-proximate"><code>lexically relative</code></a> in terms 276 of <code>std::<a name="mismatch">mismatch</a></code></h4> 277 278<p> 279 Resolves <a href="#Issue-5">issue 5</a>. Is a contributor to the 280 resolution of <a href="#Issue-8">issue 8</a>.</p> 281 282<h4> 283 <a name="Specify-op-rel-weakly">Specify</a> <a href="#op-proximate">operational <code>relative</code></a> in terms of <code> 284 <a href="#weakly_canonical">weakly_canonical</a></code></h4> 285 286<p> 287 Is a contributor to the resolution of <a href="#Issue-8">issue 8</a>.</p> 288 289<ul> 290 <li>Covers a wide range of uses cases since a single function works for 291 existing, non-existing, and partially existing paths.</li> 292 <li>Works correctly for partially existing paths that contain symlinks.</li> 293</ul> 294 295<h4> 296 <a name="Specify-op-rel-lex-rel">Specify</a> <a href="#op-proximate">operational <code>relative</code></a> in terms of 297 <a href="#lex-proximate"><code>lexically 298 relative</code></a></h4> 299 300<p> 301 Is a contributor to the resolution of <a href="#Issue-5">issue 5</a> and 302 <a href="#Issue-8">issue 8</a>.</p> 303 304<p> 305 If would be confusing to users and difficult to specify correctly if the 306 two functions had differing semantics:</p> 307<ul> 308 <li>When either or both paths are empty.</li> 309 <li>When all elements of the two paths match exactly.</li> 310 <li>Because different matching algorithms were used.</li> 311 <li>Because although the same matching algorithm was used, it was applied in different ways.</li> 312</ul> 313 314<p> 315 These problems are avoided by specifying operational <code>relative</code> 316 in terms of lexical <code>relative</code> after preparatory 317 calls to operational functions.</p> 318 319<h2><a name="Proposed-wording">Proposed wording</a></h2> 320 321<p><span style="background-color: #DBDBDB"><i>"Overview:" sections below are 322non-normative experiments attempting to make the normative reference 323specifications easier to grasp.</i></span></p> 324 325<h3><a name="Define-normal-form">Define <i>normal form</i></a></h3> 326 327<p>A path is in <b><i><a name="normal-form">normal form</a></i></b> if it has no 328redundant current directory (<i>dot</i>) or parent directory (<i>dot-dot</i>) 329elements. The normal form for an empty path is an empty path. The normal form 330for a path ending in a <i>directory-separator</i> that is not the root directory 331is the same path with a current directory (<i>dot</i>) element appended.</p> 332 333<p><span style="background-color: #DBDBDB"><i>The last sentence above is not 334necessary for POSIX-like or Windows-like operating systems, but supports systems 335like OpenVMS that use different syntax for directory and regular-file names.</i></span></p> 336 337<h3><a name="New-class-path-member-functions">New class path member functions</a></h3> 338 339<h4><a name="Synopsis-path">Synopsis</a></h4> 340 341<pre>path lexically_normal() const; 342path lexically_relative(const path& base) const; 343path lexically_proximate(const path& base) const;</pre> 344 345<h4><a name="Specification-path">Specification</a></h4> 346 347 348<pre>path <a name="lex-normal">lexically_normal</a>() const;</pre> 349<blockquote> 350<p><i>Overview:</i> Returns <code>*this</code> with redundant current directory 351(<i>dot</i>), parent directory (<i>dot-dot</i>), and <i>directory-separator</i> elements removed.</p> 352<p><i>Returns:</i> <code>*this</code> in <a href="#normal-form">normal form</a>.</p> 353<p><i>Remarks:</i> Uses <code>operator/=</code> to compose the returned path.</p> 354<p>[<i>Example:</i></p> 355<p><code>assert(path("foo/./bar/..").lexically_normal() == "foo");<br> 356assert(path("foo/.///bar/../").lexically_normal() == "foo/.");</code></p> 357<p>The above assertions will succeed.<i> </i>On Windows, the 358returned path's <i>directory-separator</i> characters will be backslashes rather than slashes, but that 359does not affect <code>path</code> equality.<i> —end example</i>]</p> 360</blockquote> 361 362<pre>path <a name="lex-relative">lexically_relative</a>(const path& base) const;</pre> 363 <blockquote> 364 <p><i>Overview:</i> Returns <code>*this</code> made relative to <code>base</code>. 365 Treats empty or identical paths as corner cases, not errors. Does not resolve 366 symlinks. Does not first normalize <code>*this</code> or <code>base</code>.</p> 367 368 <p><i>Remarks:</i> Uses <code>std::mismatch(begin(), end(), base.begin(), base.end())</code>, to determine the first mismatched element of 369 <code>*this</code> and <code>base</code>. Uses <code>operator==</code> to 370 determine if elements match. </p> 371 372 <p><i>Returns:</i> </p> 373 374 <ul> 375 <li> 376 <code>path()</code> if the first mismatched element of <code>*this</code> is equal to <code> 377 begin()</code> or the first mismatched element 378 of <code>base</code> is equal to <code>base.begin()</code>, or<br> 379 </li> 380 <li> 381 <code>path(".")</code> if the first mismatched element of <code> 382 *this</code> is equal to <code> 383 end()</code> and the first mismatched element 384 of <code>base</code> is equal to <code>base.end()</code>, or<br> 385 </li> 386 <li>An object of class <code>path</code> composed via application of <code> 387 operator/= path("..")</code> for each element in the half-open 388 range [first 389 mismatched element of <code>base</code>, <code>base.end()</code>), and then 390 application of <code>operator/=</code> for each element in the half-open 391 range 392 [first mismatched element of <code>*this</code>, <code>end()</code>). 393 </li> 394</ul> 395 396<p>[<i>Example:</i></p> 397<p><code>assert(path("/a/d").lexically_relative("/a/b/c") == "../../d");<br> 398assert(path("/a/b/c").lexically_relative("/a/d") == "../b/c");<br> 399assert(path("a/b/c").lexically_relative("a") == "b/c");<br> 400assert(path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");<br> 401assert(path("a/b/c").lexically_relative("a/b/c") == ".");<br> 402assert(path("a/b").lexically_relative("c/d") == "");</code></p> 403<p>The above assertions will succeed.<i> </i>On Windows, the 404returned path's <i>directory-separator</i>s will be backslashes rather than 405forward slashes, but that 406does not affect <code>path</code> equality.<i> —end example</i>]</p> 407 408 <p>[<i>Note:</i> If symlink following semantics are desired, use the operational function <code> 409 <a href="#op-proximate">relative</a></code> <i>—end note</i>]</p> 410 411 <p>[<i>Note:</i> If <a href="#normal">normalization</a> is needed to ensure 412 consistent matching of elements, apply <code><a href="#normal">lexically_normal()</a></code> 413 to <code>*this</code>, <code>base</code>, or both. <i>—end note</i>]</p> 414 415</blockquote> 416 417 418<pre>path <a name="lex-proximate">lexically_proximate</a>(const path& base) const;</pre> 419 420 <blockquote> 421 422 <p><i>Returns:</i> If the value of <code>lexically_relative(base)</code> is 423 not an empty path, return it. Otherwise return <code>*this</code>.</p> 424 425 <p>[<i>Note:</i> If symlink following semantics are desired, use the operational function 426 <code><a href="#op-proximate">proximate</a></code> <i>—end note</i>]</p> 427 428 <p>[<i>Note:</i> If <a href="#normal">normalization</a> is needed to ensure 429 consistent matching of elements, apply <code><a href="#normal">lexically_normal()</a></code> 430 to <code>*this</code>, <code>base</code>, or both. <i>—end note</i>]</p> 431 432</blockquote> 433 434 435<h3>New <a name="operational-functions">operational functions</a></h3> 436 437 438<h4><a name="Synopsis-ops">Synopsis</a></h4> 439 440 441<pre>path weakly_canonical(const path& p); 442path weakly_canonical(const path& p, system::error_code& ec); 443path relative(const path& p, system::error_code& ec); 444path relative(const path& p, const path& base=current_path()); 445path relative(const path& p, const path& base, system::error_code& ec); 446path proximate(const path& p, system::error_code& ec); 447path proximate(const path& p, const path& base=current_path()); 448path proximate(const path& p, const path& base, system::error_code& ec); 449</pre> 450<h4><a name="Specification-ops">Specification</a></h4> 451 452<pre>path <a name="weakly_canonical">weakly_canonical</a>(const path& p); 453path weakly_canonical(const path& p, system::error_code& ec);</pre> 454<blockquote> 455<i>Overview:</i> Returns <code>p</code> with symlinks resolved and the result 456normalized.<p> 457<i>Returns: </i> 458A path composed of the result of calling the <code>canonical</code> function on 459a path composed of the leading elements of <code>p</code> that exist, if any, 460followed by the elements of <code>p</code> that do not exist, if any.</p> 461<p><i>Postcondition:</i> The returned path is in <a href="#normal">normal form</a>.</p> 462<p><i>Remarks:</i> Uses <code>operator/=</code> to compose the returned path. 463Uses the <code>status</code> function to determine existence.</p> 464<p><i>Remarks:</i> Implementations are encouraged to avoid unnecessary 465normalization such as when <code>canonical</code> has already been called on the 466entirety of <code>p</code>.</p> 467<p><i>Throws:</i> As specified in Error reporting.</p> 468</blockquote> 469<pre>path <a name="op-relative">relative</a>(const path& p, system::error_code& ec);</pre> 470<blockquote> 471<p><i>Returns:</i> <code>relative(p, current_path(), ec)</code>.</p> 472 <p><i>Throws:</i> As specified in Error reporting.</p> 473 474 </blockquote> 475<pre>path relative(const path& p, const path& base=current_path()); 476path relative(const path& p, const path& base, system::error_code& ec);</pre> 477<blockquote> 478 <p><i>Overview:</i> Returns <code>p</code> made relative to <code> 479 base</code>. Treats empty or identical paths as corner cases, not errors. 480 Resolves symlinks and normalizes both <code>p</code> and <code>base</code> 481 before other processing.</p> 482 483<p><i>Returns:</i> <code><a href="#weakly_canonical">weakly_canonical</a>(p).l<a href="#lex-proximate">exically_relative</a>(<a href="#weakly_canonical">weakly_canonical</a>(base))</code>. The second form returns <code>path()</code> if an error occurs.</p> 484 <p><i>Throws:</i> As specified in Error reporting.</p> 485</blockquote> 486 487<pre>path <a name="op-proximate">proximate</a>(const path& p, system::error_code& ec);</pre> 488<blockquote> 489<p><i>Returns:</i> <code>proximate(p, current_path(), ec)</code>.</p> 490 <p><i>Throws:</i> As specified in Error reporting.</p> 491 492 </blockquote> 493<pre>path proximate(const path& p, const path& base=current_path()); 494path proximate(const path& p, const path& base, system::error_code& ec);</pre> 495<blockquote> 496 497<p><i>Returns:</i> <code><a href="#weakly_canonical">weakly_canonical</a>(p).l<a href="#lex-proximate">exically_proximate</a>(<a href="#weakly_canonical">weakly_canonical</a>(base))</code>. The second form returns <code>path()</code> if an error occurs.</p> 498 <p><i>Throws:</i> As specified in Error reporting.</p> 499</blockquote> 500 501<hr> 502<p>© Copyright Beman Dawes 2015</p> 503<p>Distributed under the Boost Software License, Version 1.0. See 504<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a></p> 505<p>Revised 506<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B %Y" startspan -->25 October 2015<!--webbot bot="Timestamp" endspan i-checksum="32445" --></p> 507 508</body> 509 510</html> 511