CINXE.COM

Irregular Expression: Implementing IO::Path in Rakudo

<!DOCTYPE html> <html class='v2' dir='ltr' lang='en'> <head> <link href='https://www.blogger.com/static/v1/widgets/3566091532-css_bundle_v2.css' rel='stylesheet' type='text/css'/> <meta content='width=1100' name='viewport'/> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='http://blog.brentlaabs.com/favicon.ico' rel='icon' type='image/x-icon'/> <link href='http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Irregular Expression - Atom" href="http://blog.brentlaabs.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Irregular Expression - RSS" href="http://blog.brentlaabs.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Irregular Expression - Atom" href="https://www.blogger.com/feeds/1163079349106481731/posts/default" /> <link rel="alternate" type="application/atom+xml" title="Irregular Expression - Atom" href="http://blog.brentlaabs.com/feeds/6687406856608519456/comments/default" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html' property='og:url'/> <meta content='Implementing IO::Path in Rakudo' property='og:title'/> <meta content='I started off implementing the File::Spec module for Perl 6, as explained in the last blog post , but what I really wanted to do was to get ...' property='og:description'/> <title>Irregular Expression: Implementing IO::Path in Rakudo</title> <style id='page-skin-1' type='text/css'><!-- /* ----------------------------------------------- Blogger Template Style Name: Watermark Designer: Blogger URL: www.blogger.com ----------------------------------------------- */ /* Use this with templates/1ktemplate-*.html */ /* Content ----------------------------------------------- */ body { font: normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #333333; background: #c0a154 url(https://resources.blogblog.com/blogblog/data/1kt/watermark/body_background_birds.png) repeat scroll top left; } html body .content-outer { min-width: 0; max-width: 100%; width: 100%; } .content-outer { font-size: 92%; } a:link { text-decoration:none; color: #cc3300; } a:visited { text-decoration:none; color: #993322; } a:hover { text-decoration:underline; color: #ff3300; } .body-fauxcolumns .cap-top { margin-top: 30px; background: transparent url(https://resources.blogblog.com/blogblog/data/1kt/watermark/body_overlay_birds.png) no-repeat scroll top right; height: 121px; } .content-inner { padding: 0; } /* Header ----------------------------------------------- */ .header-inner .Header .titlewrapper, .header-inner .Header .descriptionwrapper { padding-left: 20px; padding-right: 20px; } .Header h1 { font: normal normal 60px Georgia, Utopia, 'Palatino Linotype', Palatino, serif; color: #ffffff; text-shadow: 2px 2px rgba(0, 0, 0, .1); } .Header h1 a { color: #ffffff; } .Header .description { font-size: 140%; color: #997755; } /* Tabs ----------------------------------------------- */ .tabs-inner .section { margin: 0 20px; } .tabs-inner .PageList, .tabs-inner .LinkList, .tabs-inner .Labels { margin-left: -11px; margin-right: -11px; background-color: transparent; border-top: 0 solid #ffffff; border-bottom: 0 solid #ffffff; -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .3); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .3); -goog-ms-box-shadow: 0 0 0 rgba(0, 0, 0, .3); box-shadow: 0 0 0 rgba(0, 0, 0, .3); } .tabs-inner .PageList .widget-content, .tabs-inner .LinkList .widget-content, .tabs-inner .Labels .widget-content { margin: -3px -11px; background: transparent none no-repeat scroll right; } .tabs-inner .widget ul { padding: 2px 25px; max-height: 34px; background: transparent none no-repeat scroll left; } .tabs-inner .widget li { border: none; } .tabs-inner .widget li a { display: inline-block; padding: .25em 1em; font: normal normal 20px Georgia, Utopia, 'Palatino Linotype', Palatino, serif; color: #cc3300; border-right: 1px solid #c0a154; } .tabs-inner .widget li:first-child a { border-left: 1px solid #c0a154; } .tabs-inner .widget li.selected a, .tabs-inner .widget li a:hover { color: #000000; } /* Headings ----------------------------------------------- */ h2 { font: normal normal 20px Georgia, Utopia, 'Palatino Linotype', Palatino, serif; color: #000000; margin: 0 0 .5em; } h2.date-header { font: normal normal 16px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #997755; } /* Main ----------------------------------------------- */ .main-inner .column-center-inner, .main-inner .column-left-inner, .main-inner .column-right-inner { padding: 0 5px; } .main-outer { margin-top: 0; background: transparent none no-repeat scroll top left; } .main-inner { padding-top: 30px; } .main-cap-top { position: relative; } .main-cap-top .cap-right { position: absolute; height: 0; width: 100%; bottom: 0; background: transparent none repeat-x scroll bottom center; } .main-cap-top .cap-left { position: absolute; height: 245px; width: 280px; right: 0; bottom: 0; background: transparent none no-repeat scroll bottom left; } /* Posts ----------------------------------------------- */ .post-outer { padding: 15px 20px; margin: 0 0 25px; background: transparent url(https://resources.blogblog.com/blogblog/data/1kt/watermark/post_background_birds.png) repeat scroll top left; _background-image: none; border: dotted 1px #ccbb99; -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .1); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .1); -goog-ms-box-shadow: 0 0 0 rgba(0, 0, 0, .1); box-shadow: 0 0 0 rgba(0, 0, 0, .1); } h3.post-title { font: normal normal 30px Georgia, Utopia, 'Palatino Linotype', Palatino, serif; margin: 0; } .comments h4 { font: normal normal 30px Georgia, Utopia, 'Palatino Linotype', Palatino, serif; margin: 1em 0 0; } .post-body { font-size: 105%; line-height: 1.5; position: relative; } .post-header { margin: 0 0 1em; color: #997755; } .post-footer { margin: 10px 0 0; padding: 10px 0 0; color: #997755; border-top: dashed 1px #777777; } #blog-pager { font-size: 140% } #comments .comment-author { padding-top: 1.5em; border-top: dashed 1px #777777; background-position: 0 1.5em; } #comments .comment-author:first-child { padding-top: 0; border-top: none; } .avatar-image-container { margin: .2em 0 0; } /* Comments ----------------------------------------------- */ .comments .comments-content .icon.blog-author { background-repeat: no-repeat; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9sLFwMeCjjhcOMAAAD+SURBVDjLtZSvTgNBEIe/WRRnm3U8RC1neQdsm1zSBIU9VVF1FkUguQQsD9ITmD7ECZIJSE4OZo9stoVjC/zc7ky+zH9hXwVwDpTAWWLrgS3QAe8AZgaAJI5zYAmc8r0G4AHYHQKVwII8PZrZFsBFkeRCABYiMh9BRUhnSkPTNCtVXYXURi1FpBDgArj8QU1eVXUzfnjv7yP7kwu1mYrkWlU33vs1QNu2qU8pwN0UpKoqokjWwCztrMuBhEhmh8bD5UDqur75asbcX0BGUB9/HAMB+r32hznJgXy2v0sGLBcyAJ1EK3LFcbo1s91JeLwAbwGYu7TP/3ZGfnXYPgAVNngtqatUNgAAAABJRU5ErkJggg==); } .comments .comments-content .loadmore a { border-top: 1px solid #777777; border-bottom: 1px solid #777777; } .comments .continue { border-top: 2px solid #777777; } /* Widgets ----------------------------------------------- */ .widget ul, .widget #ArchiveList ul.flat { padding: 0; list-style: none; } .widget ul li, .widget #ArchiveList ul.flat li { padding: .35em 0; text-indent: 0; border-top: dashed 1px #777777; } .widget ul li:first-child, .widget #ArchiveList ul.flat li:first-child { border-top: none; } .widget .post-body ul { list-style: disc; } .widget .post-body ul li { border: none; } .widget .zippy { color: #777777; } .post-body img, .post-body .tr-caption-container, .Profile img, .Image img, .BlogList .item-thumbnail img { padding: 5px; background: #fff; -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, .5); -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .5); -goog-ms-box-shadow: 1px 1px 5px rgba(0, 0, 0, .5); box-shadow: 1px 1px 5px rgba(0, 0, 0, .5); } .post-body img, .post-body .tr-caption-container { padding: 8px; } .post-body .tr-caption-container { color: #333333; } .post-body .tr-caption-container img { padding: 0; background: transparent; border: none; -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .1); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .1); -goog-ms-box-shadow: 0 0 0 rgba(0, 0, 0, .1); box-shadow: 0 0 0 rgba(0, 0, 0, .1); } /* Footer ----------------------------------------------- */ .footer-outer { color:#ccbb99; background: #330000 url(https://resources.blogblog.com/blogblog/data/1kt/watermark/body_background_navigator.png) repeat scroll top left; } .footer-outer a { color: #ff7755; } .footer-outer a:visited { color: #dd5533; } .footer-outer a:hover { color: #ff9977; } .footer-outer .widget h2 { color: #eeddbb; } /* Mobile ----------------------------------------------- */ body.mobile { background-size: 100% auto; } .mobile .body-fauxcolumn-outer { background: transparent none repeat scroll top left; } html .mobile .mobile-date-outer { border-bottom: none; background: transparent url(https://resources.blogblog.com/blogblog/data/1kt/watermark/post_background_birds.png) repeat scroll top left; _background-image: none; margin-bottom: 10px; } .mobile .main-inner .date-outer { padding: 0; } .mobile .main-inner .date-header { margin: 10px; } .mobile .main-cap-top { z-index: -1; } .mobile .content-outer { font-size: 100%; } .mobile .post-outer { padding: 10px; } .mobile .main-cap-top .cap-left { background: transparent none no-repeat scroll bottom left; } .mobile .body-fauxcolumns .cap-top { margin: 0; } .mobile-link-button { background: transparent url(https://resources.blogblog.com/blogblog/data/1kt/watermark/post_background_birds.png) repeat scroll top left; } .mobile-link-button a:link, .mobile-link-button a:visited { color: #cc3300; } .mobile-index-date .date-header { color: #997755; } .mobile-index-contents { color: #333333; } .mobile .tabs-inner .section { margin: 0; } .mobile .tabs-inner .PageList { margin-left: 0; margin-right: 0; } .mobile .tabs-inner .PageList .widget-content { margin: 0; color: #000000; background: transparent url(https://resources.blogblog.com/blogblog/data/1kt/watermark/post_background_birds.png) repeat scroll top left; } .mobile .tabs-inner .PageList .widget-content .pagelist-arrow { border-left: 1px solid #c0a154; } .striped-table .odd { background-color: #DCCBA1; } --></style> <style id='template-skin-1' type='text/css'><!-- body { min-width: 960px; } .content-outer, .content-fauxcolumn-outer, .region-inner { min-width: 960px; max-width: 960px; _width: 960px; } .main-inner .columns { padding-left: 0px; padding-right: 310px; } .main-inner .fauxcolumn-center-outer { left: 0px; right: 310px; /* IE6 does not respect left and right together */ _width: expression(this.parentNode.offsetWidth - parseInt("0px") - parseInt("310px") + 'px'); } .main-inner .fauxcolumn-left-outer { width: 0px; } .main-inner .fauxcolumn-right-outer { width: 310px; } .main-inner .column-left-outer { width: 0px; right: 100%; margin-left: -0px; } .main-inner .column-right-outer { width: 310px; margin-right: -310px; } #layout { min-width: 0; } #layout .content-outer { min-width: 0; width: 800px; } #layout .region-inner { min-width: 0; width: auto; } body#layout div.add_widget { padding: 8px; } body#layout div.add_widget a { margin-left: 32px; } --></style> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=1163079349106481731&amp;zx=c92d9171-713d-414c-963f-50bec28b445b' media='none' onload='if(media!=&#39;all&#39;)media=&#39;all&#39;' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=1163079349106481731&amp;zx=c92d9171-713d-414c-963f-50bec28b445b' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> </head> <body class='loading variant-birds'> <div class='navbar section' id='navbar' name='Navbar'><div class='widget Navbar' data-version='1' id='Navbar1'><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar/1163079349106481731?po\x3d6687406856608519456\x26origin\x3dhttp://blog.brentlaabs.com', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script><script type="text/javascript"> (function() { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = '//pagead2.googlesyndication.com/pagead/js/google_top_exp.js'; var head = document.getElementsByTagName('head')[0]; if (head) { head.appendChild(script); }})(); </script> </div></div> <div class='body-fauxcolumns'> <div class='fauxcolumn-outer body-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content'> <div class='content-fauxcolumns'> <div class='fauxcolumn-outer content-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content-outer'> <div class='content-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left content-fauxborder-left'> <div class='fauxborder-right content-fauxborder-right'></div> <div class='content-inner'> <header> <div class='header-outer'> <div class='header-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left header-fauxborder-left'> <div class='fauxborder-right header-fauxborder-right'></div> <div class='region-inner header-inner'> <div class='header section' id='header' name='Header'><div class='widget Header' data-version='1' id='Header1'> <div id='header-inner'> <div class='titlewrapper'> <h1 class='title'> <a href='http://blog.brentlaabs.com/'> Irregular Expression </a> </h1> </div> <div class='descriptionwrapper'> <p class='description'><span>Brent Laabs on programming and culture</span></p> </div> </div> </div></div> </div> </div> <div class='header-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </header> <div class='tabs-outer'> <div class='tabs-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left tabs-fauxborder-left'> <div class='fauxborder-right tabs-fauxborder-right'></div> <div class='region-inner tabs-inner'> <div class='tabs no-items section' id='crosscol' name='Cross-Column'></div> <div class='tabs no-items section' id='crosscol-overflow' name='Cross-Column 2'></div> </div> </div> <div class='tabs-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='main-outer'> <div class='main-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left main-fauxborder-left'> <div class='fauxborder-right main-fauxborder-right'></div> <div class='region-inner main-inner'> <div class='columns fauxcolumns'> <div class='fauxcolumn-outer fauxcolumn-center-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-left-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-right-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <!-- corrects IE6 width calculation --> <div class='columns-inner'> <div class='column-center-outer'> <div class='column-center-inner'> <div class='main section' id='main' name='Main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='blog-posts hfeed'> <div class="date-outer"> <h2 class='date-header'><span>Wednesday, May 8, 2013</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='1163079349106481731' itemprop='blogId'/> <meta content='6687406856608519456' itemprop='postId'/> <a name='6687406856608519456'></a> <h3 class='post-title entry-title' itemprop='name'> Implementing IO::Path in Rakudo </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-6687406856608519456' itemprop='description articleBody'> I started off implementing the File::Spec module for Perl 6, <a href="http://blog.brentlaabs.com/2013/05/porting-module-to-perl-6.html">as explained in the last blog post</a>, but what I really wanted to do was to get some sanity in working with paths through IO::Path objects.&nbsp; And if I was going to do this, I needed to actually edit the core modules of Rakudo.<br /> <br /> Starting with a module which does stringy operations on directory paths, I set out with the goal of making some sort of easy-to-use, path manipulation class in the core.&nbsp; Something like how <a href="http://search.cpan.org/~kwilliams/Path-Class-0.31/lib/Path/Class.pm">Path::Class</a> works in Perl 5.&nbsp; Then I looked at <a href="http://perlcabal.org/syn/S32/IO.html">S32::IO</a>, and realized that IO::Path was exactly what I was seeking.&nbsp; But it was only partially implemented, and only for POSIX.<br /> <br /> So I'm going to walk through the steps I took to integrate multiple-OS path support into Rakudo, in the hopes that it will help other people to avoid my mistakes.&nbsp; Which were fairly numerous. :/<br /> <br /> This was my first foray into hacking a compiler, and I must confess it was fairly intimidating.&nbsp; I'm no script kiddie, but I hadn't worked on any large open-source projects before.&nbsp; However, the setting is made of Perl 6 code, so it was more or less a matter of integrating what FROGGS and I had already written.<br /> <br /> <h3> Baby's first steps</h3> <br /> I had played around with using File::Spec as a backend to an IO::Path in the <a href="https://github.com/labster/p6-IO-Path-More">IO::Path::More module</a>, so it became clear that this was the best way forward for Rakudo.&nbsp; <br /> <br /> I realized right away that IO::Path's interface would have to change to include systems with a concept of volume.&nbsp; I did a small edit to IO.pm to add a <code>$.volume</code> attribute, changed a few lines of code in <code>sub dir</code>, and compiled.&nbsp; Everything worked.&nbsp; I sent a pull request into Rakudo, just to get the interface-changing out of the way first.&nbsp; It tested okay, and was accepted.&nbsp; Wow, I'm good at this!<br /> <br /> Naturally, it all got worse from there.<br /> <br /> <h3> Problem 1: Biting off more than I can chew</h3> <br /> The next step was to add the File::Spec modules into the core.&nbsp; So I just started by copying over the .pm files into the core directory.&nbsp; Unlike in normal Perl code, the modules aren't included with <code>use Module;</code>.&nbsp; Instead, I edited the <code>Makefile.in</code> to add the modules in the correct order.<br /> <br /> Since the File::Spec object needs to inherit from the subclasses, and the other subclasses inherit from File::Spec::Unix, I went with this order:&nbsp; File::Spec::Unix, File::Spec::Win32, File::Spec::Cygwin, File::Spec.&nbsp; Now, some of you might already see a problem with that.&nbsp; To them, I say: "Shh!&nbsp; No spoilers!"<br /> <br /> I realized that I couldn't use the file-scoped class definition (<code>class Foo;</code>) if it was going to end up all in one file, so I switched those out for curly braces.&nbsp; Then I rebuilt the makefile and compiled rakudo.<br /> <br /> That generated a whole mess of errors.&nbsp; And not all nice errors like before -- Exception.pm hadn't even loaded yet!&nbsp; This was a bunch of nqp recursion errors.&nbsp; I tried scaling back a little at a time, even commenting out the entire inside of classes, but I still had issues building Rakudo.&nbsp; Eventually, I had to scale back my approach, and add files to the build one at a time.<br /> <br /> <h3> Problem 2: Inheritance</h3> <br /> It turned out that each file in my additions had it's own unique problems.&nbsp; The first was well, it seemed like File::Spec::Unix just, well, disappeared.&nbsp; Unless I completely removed the File::Spec class, and then it worked.<br /> <br /> When you declare a subclass, you're actually adding to the main class' package.&nbsp; So File::Spec::Unix is really <code>File::Spec.WHO&lt;Unix&gt;</code>.&nbsp; So if you initialize File::Spec after File::Spec::Unix, it nukes the previous package and its symbol table.&nbsp; This problem was a lot of no fun to figure out, and I'm glad moritz++ and jnthn++ walked me through it.<br /> <br /> The solution here was simple enough -- stub out File::Spec with <code>class File::Spec { ... }</code> before creating File::Spec::Unix.&nbsp; This is enough to make sure File::Spec will be able to refer to its children.<br /> <br /> Although... the last thing I need is some yahoo doing <code>my class File</code> and then complaining about why they can't load File::Spec.&nbsp; So it was at this time I decided to change File::Spec to IO::Spec.&nbsp; Making a File class I can see -- if you decide to replace class IO, then you deserve what you get.<br /> <br /> <h3> Problem 3: The language is in the process of building</h3> <br /> The setting may feel like normal Perl code, but it's not.&nbsp; It's still in the process of being built.&nbsp; It's like a house in the process of construction.&nbsp; If there's only a wood frame, you can still hang a portrait on the "walls" -- but this will only get in the way when it's time to hang the drywall.&nbsp; Things need to come together in the correct order.<br /> <br /> I encountered these problems in a couple of different ways.&nbsp; The first was in using <code>rx//</code> to precompile some patterns before Regex.pm was loaded.&nbsp; Windows-style paths really need this for readablity, because they use both kinds of slashes as separators and the concept of volume is fairly complicated.&nbsp; I tried a lot of different ways of formatting, each of which made the build fail in new and unique ways. Then I discovered <code>MAKE_REGEX()</code> had loaded a bit before the IO modules.&nbsp; This particular problem seemed to be solved.<br /> <br /> The next couple of problems were caused by <code>$*OS</code> not being in scope at build time, as terms.pm was way, way down at the end.&nbsp; It works just fine in method calls, but if it's needed as a class attribute, it's simply not in scope when you're building the class.&nbsp; I ended up replicating the same op used in terms.pm to get the kernel string, so I could have it available earlier.&nbsp; Early enough to figure out which subclass of IO::Spec to use for the main object.<br /> <br /> So remember, object building happens right away, but subs and methods can carry references to things that happen later.<br /> <br /> <h3> Problem 4: <code>Br</code>eaking <code>Pa</code>nda</h3> <br /> Everything seemed like it was working pretty okay at this point.&nbsp; Until I got to the day of the masakism IRC seminar.&nbsp; It was at this point that tried to install a module for the class, so I couldn't help but notice that Panda seemed to die horribly.&nbsp; I checked out and built the nom branch to use for the duration, but I really had no idea what was going on.<br /> <br /> When I golfed the breakage in Panda, it came down to its "use lib" line -- and lib.pm is shockingly simple.&nbsp; Running <code>use lib 'foo'</code> in the REPL alternated between three different errors from the NQP level.&nbsp; Something was seriously wrong.<br /> <br /> My only choice was to work backwards, and see what was causing the problem.&nbsp; I would say <code>git bisect</code> here, but I hadn't actually been making enough commits to effectively get at the problem.&nbsp; So that was the first learning experience here -- commit any time you think you have functional code.<br /> <br /> Anyway, it took a lot of edits, and I got most of the way through a novel while waiting for Rakudo to recompile, but I eventually traced it back to the precompiled regexes that were giving me a problem earlier.&nbsp; At this point I was about to give up, and make long, ugly regexes. Finally jnthn++ noted that Regex.pm hadn't loaded when this was trying to run, so I should just move all of the IO modules to later in the build.<br /> <br /> So I swapped back in the <code>rx//</code> syntax, and naturally, it all worked.&nbsp; The lesson here is that running some real software can pick up bugs (although the spectests would have shown it too).&nbsp; And that you really do need to make sure that dependencies come earlier.&nbsp; And most of all, if you're stuck, just ask in #perl6.<br /> <br /> <h3> Spectesting</h3> <br /> The methods I developed for IO::Path::More to IO::Path went in painlessly.&nbsp; I ended up writing an additional set of methods for IO::Spec -- <code>.split</code> and <code>.join</code>, to replace <code>.splitpath</code> and <code>.catpath</code> but with <code>basename</code> and <code>dirname</code> syntax.&nbsp; That allows IO::Path.basename to always have the current item in question, and all of the trailing slashes are gone.<br /> <br /> It was at this point where I started thinking about testing.&nbsp; IO::Spec had literally hundreds of tests from File::Spec in Perl 5.&nbsp; But ironically, IO::Spec wasn't actually specced.&nbsp; So the question became, should IO::Spec be just a backend, or a fully specified part of Perl 6?<br /> <br /> Implementations in Perl 6 are supposed to inform the spec, as well as the other way around.&nbsp; And the more I thought about it, *something* has to do the low-level string operations on paths.&nbsp; And there is no reason to hide it, either.&nbsp; Rakudo already provides access to all of its lower layers via nqp or pir ops, so it made sense to include it as a specced part of Perl 6.<br /> <br /> So I went ahead and edited the Specification for S32::IO, adding IO::Spec and several methods for manipulating IO::Paths.&nbsp; Lots of text.&nbsp; And then even more went into writing tests for IO::Path.&nbsp; Naturally, these uncovered some more minor bugs, but that's what tests are for.<br /> <br /> <h3> Patch Approved</h3> <br /> It didn't take all that long for my pull request to get merged, especially after I started writing tests.&nbsp; This whole process took about three weeks.&nbsp; I'll have a few minor cleanup I'm going to have to do in the next couple of days, as I resolve a bug in using IO::Spec::Unix.rel2abs.&nbsp; Parrot just added a readlink op on my request, so IO::Path.resolve should be working soon.<br /> <br /> And what we have to show for all this work is a Perl 6 implementation that does file path modifications on Linux, Cygwin, or Windows/DOS.<br /> <code>&nbsp;&nbsp;&nbsp; On Linux:<br />&nbsp;&nbsp;&nbsp; "/foo/./bar//"\&nbsp;&nbsp; .path.cleanup.parent;&nbsp; #yields "/foo"<br />&nbsp;&nbsp;&nbsp; On Windows: <br />&nbsp;&nbsp;&nbsp; "C:/foo\\.\\bar\\".path.cleanup.parent;&nbsp; #yields "C:\foo"<br />&nbsp;&nbsp;&nbsp; On any platform:<br />&nbsp;&nbsp;&nbsp; IO::Path::Win32.new("C:/baz").volume;&nbsp;&nbsp;&nbsp; #yields "C:"</code><br /> I never finished VMS, or Mac Classic, but at this point, they can just be dropped in, by adding a new IO::Spec subclass.<br /> <br /> So there it is, at long last: sanity in file paths in Perl.&nbsp; I think, if I had known how it was going to go from the beginning, I would have been even <i>more</i> intimidated.&nbsp; Even so, it was just the same kind of debugging I'm used to in modules.&nbsp; Only without the safety rails of the parser and a much longer build time.<br /> <br /> But if you can write a module and a class in Perl 6, you already have most of the skills to contribute to the setting.&nbsp; A compiler with internals that feel like a high-level scripting language:&nbsp; that, like digital watches, is a pretty neat idea. <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/17518100165641296059' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/17518100165641296059' rel='author' title='author profile'> <span itemprop='name'>Brent Laabs</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html' itemprop='url'/> <a class='timestamp-link' href='http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2013-05-08T01:02:00-07:00'>1:02&#8239;AM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-758962430'> <a href='https://www.blogger.com/post-edit.g?blogID=1163079349106481731&postID=6687406856608519456&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='http://blog.brentlaabs.com/search/label/debugging' rel='tag'>debugging</a>, <a href='http://blog.brentlaabs.com/search/label/perl6' rel='tag'>perl6</a>, <a href='http://blog.brentlaabs.com/search/label/programming' rel='tag'>programming</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> <div class='comments' id='comments'> <a name='comments'></a> <h4>No comments:</h4> <div id='Blog1_comments-block-wrapper'> <dl class='avatar-comment-indent' id='comments-block'> </dl> </div> <p class='comment-footer'> <div class='comment-form'> <a name='comment-form'></a> <h4 id='comment-post-message'>Post a Comment</h4> <p> </p> <a href='https://www.blogger.com/comment/frame/1163079349106481731?po=6687406856608519456&hl=en' id='comment-editor-src'></a> <iframe allowtransparency='true' class='blogger-iframe-colorize blogger-comment-from-post' frameborder='0' height='410px' id='comment-editor' name='comment-editor' src='' width='100%'></iframe> <script src='https://www.blogger.com/static/v1/jsbin/681870030-comment_from_post_iframe.js' type='text/javascript'></script> <script type='text/javascript'> BLOG_CMT_createIframe('https://www.blogger.com/rpc_relay.html'); </script> </div> </p> </div> </div> </div></div> </div> <div class='blog-pager' id='blog-pager'> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='http://blog.brentlaabs.com/2013/05/how-to-start-hacking-on-rakudo-perl-6.html' id='Blog1_blog-pager-newer-link' title='Newer Post'>Newer Post</a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='http://blog.brentlaabs.com/2013/05/porting-module-to-perl-6.html' id='Blog1_blog-pager-older-link' title='Older Post'>Older Post</a> </span> <a class='home-link' href='http://blog.brentlaabs.com/'>Home</a> </div> <div class='clear'></div> <div class='post-feeds'> <div class='feed-links'> Subscribe to: <a class='feed-link' href='http://blog.brentlaabs.com/feeds/6687406856608519456/comments/default' target='_blank' type='application/atom+xml'>Post Comments (Atom)</a> </div> </div> </div></div> </div> </div> <div class='column-left-outer'> <div class='column-left-inner'> <aside> </aside> </div> </div> <div class='column-right-outer'> <div class='column-right-inner'> <aside> <div class='sidebar section' id='sidebar-right-1'><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <h2>Blog Archive</h2> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2018/'> 2018 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2018/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2017/'> 2017 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2017/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2015/'> 2015 </a> <span class='post-count' dir='ltr'>(2)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2015/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2015/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2014/'> 2014 </a> <span class='post-count' dir='ltr'>(2)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2014/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2014/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2013/'> 2013 </a> <span class='post-count' dir='ltr'>(10)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2013/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2013/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2013/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2013/05/'> May </a> <span class='post-count' dir='ltr'>(3)</span> <ul class='posts'> <li><a href='http://blog.brentlaabs.com/2013/05/how-to-start-hacking-on-rakudo-perl-6.html'>How to start hacking on Rakudo Perl 6</a></li> <li><a href='http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html'>Implementing IO::Path in Rakudo</a></li> <li><a href='http://blog.brentlaabs.com/2013/05/porting-module-to-perl-6.html'>Porting a Module to Perl 6</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.brentlaabs.com/2013/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> </div> </div> <div class='clear'></div> </div> </div><div class='widget Profile' data-version='1' id='Profile1'> <h2>About Me</h2> <div class='widget-content'> <dl class='profile-datablock'> <dt class='profile-data'> <a class='profile-name-link g-profile' href='https://www.blogger.com/profile/17518100165641296059' rel='author' style='background-image: url(//www.blogger.com/img/logo-16.png);'> Brent Laabs </a> </dt> <dd class='profile-data'>Ventura, California, United States</dd> <dd class='profile-textblock'>Programmer, writer, gamer, analyst, anime watcher, and wiki editor.</dd> </dl> <a class='profile-link' href='https://www.blogger.com/profile/17518100165641296059' rel='author'>View my complete profile</a> <div class='clear'></div> </div> </div></div> </aside> </div> </div> </div> <div style='clear: both'></div> <!-- columns --> </div> <!-- main --> </div> </div> <div class='main-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <footer> <div class='footer-outer'> <div class='footer-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left footer-fauxborder-left'> <div class='fauxborder-right footer-fauxborder-right'></div> <div class='region-inner footer-inner'> <div class='foot no-items section' id='footer-1'></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='foot no-items section' id='footer-2-1'></div> </td> <td class='columns-cell'> <div class='foot no-items section' id='footer-2-2'></div> </td> </tr> </tbody> </table> <!-- outside of the include in order to lock Attribution widget --> <div class='foot section' id='footer-3' name='Footer'><div class='widget Attribution' data-version='1' id='Attribution1'> <div class='widget-content' style='text-align: center;'> Watermark theme. Powered by <a href='https://www.blogger.com' target='_blank'>Blogger</a>. </div> <div class='clear'></div> </div></div> </div> </div> <div class='footer-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </footer> <!-- content --> </div> </div> <div class='content-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <script type='text/javascript'> window.setTimeout(function() { document.body.className = document.body.className.replace('loading', ''); }, 10); </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/2074308869-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY4ga_5Bh15u70hgYQOWKADnASbpXQ:1743051512062';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d1163079349106481731','//blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html','1163079349106481731'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '1163079349106481731', 'title': 'Irregular Expression', 'url': 'http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html', 'canonicalUrl': 'http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html', 'homepageUrl': 'http://blog.brentlaabs.com/', 'searchUrl': 'http://blog.brentlaabs.com/search', 'canonicalHomepageUrl': 'http://blog.brentlaabs.com/', 'blogspotFaviconUrl': 'http://blog.brentlaabs.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': true, 'httpsEnabled': false, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': '', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Irregular Expression - Atom\x22 href\x3d\x22http://blog.brentlaabs.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Irregular Expression - RSS\x22 href\x3d\x22http://blog.brentlaabs.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Irregular Expression - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/1163079349106481731/posts/default\x22 /\x3e\n\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Irregular Expression - Atom\x22 href\x3d\x22http://blog.brentlaabs.com/feeds/6687406856608519456/comments/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/cbe0cd4e6298c445', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'item', 'postId': '6687406856608519456', 'pageName': 'Implementing IO::Path in Rakudo', 'pageTitle': 'Irregular Expression: Implementing IO::Path in Rakudo'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'Watermark', 'localizedName': 'Watermark', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': false, 'variant': 'birds', 'variantId': 'birds'}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Implementing IO::Path in Rakudo', 'description': 'I started off implementing the File::Spec module for Perl 6, as explained in the last blog post , but what I really wanted to do was to get ...', 'url': 'http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html', 'type': 'item', 'isSingleItem': true, 'isMultipleItems': false, 'isError': false, 'isPage': false, 'isPost': true, 'isHomepage': false, 'isArchive': false, 'isLabelSearch': false, 'postId': 6687406856608519456}}]); _WidgetManager._RegisterWidget('_NavbarView', new _WidgetInfo('Navbar1', 'navbar', document.getElementById('Navbar1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'lightboxEnabled': true, 'lightboxModuleUrl': 'https://www.blogger.com/static/v1/jsbin/2223122975-lbx.js', 'lightboxCssUrl': 'https://www.blogger.com/static/v1/v-css/1964470060-lightbox_bundle.css'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar-right-1', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_ProfileView', new _WidgetInfo('Profile1', 'sidebar-right-1', document.getElementById('Profile1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull')); </script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10