<?xml version="1.0" encoding="us-ascii"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Perl Advent Calendar 2015</title><id>http://perladvent.org/2015/</id><link href="http://perladvent.org/2015/atom.xml" rel="self"/><updated>2026-04-14T18:25:01Z</updated><author><name>Mark Fowler</name></author><generator uri="https://metacpan.org/pod/XML::Atom::SimpleFeed" version="0.905">XML::Atom::SimpleFeed</generator><entry><title>One More Thing</title><link href="http://perladvent.org/2015/2015-12-25.html"/><id>http://perladvent.org/2015/2015-12-25.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Merry Christmas, Happy Holidays, and good tidings to you all. We&#38;#39;ve concluded the sixteenth annual Perl Advent Calendar in good cheer and good spirits.&lt;/p&gt;

&lt;h3 id=&#34;Without-You-This-Would-Not-Be-Possible&#34;&gt;Without You This Would Not Be Possible&lt;/h3&gt;

&lt;p&gt;The Perl Advent Calendar is a team effort, and it wouldn&#38;#39;t be possible to produce it without the help from everyone involved. This year thanks are due for the contributions made by Alex Balhatchet, Arthur Axel &#38;quot;fREW&#38;quot; Schmidt, Dave Cross, Dave Rolsky, David Cantrell, David Precious, Graham Ollis, Ivan Kruglov, James Laver, Johann Rolschewski, Marcus Ramberg, Mark Fowler, Masayuki Matsuki, Neil Bowers, Olaf Alders, openstrike, Pete Houston, Paul &#38;quot;LeoNerd&#38;quot; Evans, Ricardo SIGNES, Sergey Romanov, Shoichi Kaji, and Yanick Champoux. Thanks everyone!&lt;/p&gt;

&lt;p&gt;And of course, it wouldn&#38;#39;t be possible without all the readers enjoying the articles each day, so thanks to you too.&lt;/p&gt;

&lt;p&gt;In early February 2016 I&#38;#39;ll be starting the whole process over again with a call for participation for the 2016 Perl Advent Calendar. If you&#38;#39;re reading then then I&#38;#39;d strongly recommend you write an article, especially if you&#38;#39;ve not written one before!&lt;/p&gt;

&lt;h3 id=&#34;The-Gift-of-The-CPAN&#34;&gt;The Gift of The CPAN&lt;/h3&gt;

&lt;p&gt;Advent may be once again over but the CPAN is the gift that keeps on giving, and each year it gets better and better!&lt;/p&gt;

&lt;p&gt;Right now as I write this the CPAN has one hundred and fifty eight thousand five hundred and fifty nine modules published to it. That means that - in addition to updates to existing modules - since I wrote this Christmas Day entry last year for the 2014 Advent Calendar sixteen thousand eight hundred and ten new modules have been uploaded, or in other words a growth of nearly 12% in just one year!&lt;/p&gt;

&lt;p&gt;To put this in some context, if you took just five minutes to install, examine and play with each of these new modules it&#38;#39;d be nearly the end of February before you were done (If you were to do the same for every module on the CPAN...you&#38;#39;d miss next year&#38;#39;s advent calendar totally and you&#38;#39;d finally be done in June 2017!) That is, assuming of course, you didn&#38;#39;t stop to sleep or eat or anything else.&lt;/p&gt;

&lt;p&gt;This sounds like a lot of work! Where can you find out about all this the &lt;i&gt;lazy&lt;/i&gt; way? As always:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You can search for Perl modules at &lt;a href=&#34;https://metacpan.org/&#34;&gt;metacpan&lt;/a&gt;
  where you can also see a list of &lt;a href=&#34;https://metacpan.org/recent&#34;&gt;recently
  published modules&lt;/li&gt;&lt;li&gt;&lt;a href=&#34;http://cpanratings.perl.org/&#34;&gt;CPAN Ratings&lt;/a&gt; offers a ratings
  and reviews of Perl modules.  It&#39;s like a democratic advent calendar each day
  of the year!&lt;/li&gt;
  &lt;li&gt;The &lt;a href=&#34;http://perlweekly.com/&#34;&gt;Perl Weekly&lt;/a&gt; provides one small
  succinct email a week with a summary of the interesting things happing in Perl
  that week, including new modules, interesting articles and upcoming events.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&#34;http://blogs.perl.org/&#34;&gt;blogs.perl.org&lt;/a&gt; hosts a vast number of
  Perl blogs if you&#39;re looking for more articles to read throughout the year.  The &lt;a href=&#34;http://ironman.enlightenedperl.org/&#34;&gt;
  Perl Ironman Challenge&lt;/a&gt; links to a lot more blogs as part of the &lt;em&gt;updating
  your Perl blog weekly&lt;/em&gt; challenge&lt;/li&gt;
  &lt;li&gt;Of course, if you want more Perl Advent articles, there&#39;s always the
  previous &lt;a href=&#34;http://perladvent.org/archives.html&#34;&gt;fifteen years of advent
  calendar&lt;/a&gt; to go through.  Happy reading!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;That-One-More-Thing&#34;&gt;That One More Thing&lt;/h3&gt;

&lt;p&gt;This Christmas is the Christmas many in the Perl community have been waiting for: The one where we get a whole new programming language!&lt;/p&gt;

&lt;p&gt;Perl 6 is a sister language to Perl 5: Rebuilt from scratch, with exciting refined syntax and capabilities, Perl 6 is designed to appeal to the discerning Perl programmer. It&#38;#39;s been under development for many years, but finally this Christmas we&#38;#39;re getting all our Christmases at once: The first major release!&lt;/p&gt;

&lt;p&gt;You can find out more about Perl 6 over at &lt;a href=&#34;http://perl6.org/&#34;&gt;perl6.org&lt;/a&gt;. Heck, they&#38;#39;ve even got their own &lt;a href=&#34;https://perl6advent.wordpress.com/&#34;&gt;advent calendar&lt;/a&gt;...&lt;/p&gt;

&lt;p&gt;Until next year....Merry Christmas, one and all.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2015-12-25T00:00:00Z</updated><category term="Perl"/><author><name>Mark Fowler</name></author></entry><entry><title>The Perl Powered Christmas Tree</title><link href="http://perladvent.org/2015/2015-12-24.html"/><id>http://perladvent.org/2015/2015-12-24.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;So, you want to run some Christmas tree lights. Not just any lights, but flashy blinky ones. And while you&#38;#39;re at it, give them some nice pretty patterns using a few separate chains of lamps. Maybe Perl can help run those patterns?&lt;/p&gt;

&lt;h3 id=&#34;The-Software&#34;&gt;The Software&lt;/h3&gt;

&lt;p&gt;It&#38;#39;s simple enough of course to define some blinky patterns, perhaps by naming the light chains A to D, and using a sequence of strings to define the patterns of which ones should be on or off:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@patterns&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;AB CD AB CD AB CD AC BD AC BD AC BD BC AD BC AD BC AD ...&lt;br /&gt;)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We could then use this string of patterns to drive the lights in some manner. For example, we could do something simple:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Time::HiRes&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;sleep&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$pattern&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@patterns&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;set_lights&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$pattern&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;sleep&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we&#38;#39;ve got a nice simple repeating pattern that just runs all day long. But how might we implement this &lt;code&gt;set_lights()&lt;/code&gt; function? We&#38;#39;ll have to actually communicate with the outside world somehow; some actual piece of hardware.&lt;/p&gt;

&lt;p&gt;Two specific pieces of hardware that could be useful here are the FTDI FT232H (most conveniently on a breakout board, such as the &lt;a href=&#34;https://www.adafruit.com/products/2264&#34;&gt;one made by Adafruit&lt;/a&gt;) and the Bus Pirate Made by &lt;a href=&#34;http://dangerousprototypes.com/docs/Bus_Pirate&#34;&gt;Dangerous Prototypes&lt;/a&gt;, available from several places&lt;/p&gt;

&lt;p&gt;These two devices are somewhat different in many respects, but both of them may be described as a USB-attached board which has several digital logic IO pins on board. They each support a mode of operation whereby several pins on the board (16 in the FTDI&#38;#39;s case, 5 in the Bus Pirate) can be controlled directly by the computer, setting them directly high or low as required by the program. In our case we only need 4 for the light patterns described above so either would be sufficient for our purposes.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&#34;https://metacpan.org/module/Device::Chip&#34;&gt;Device::Chip&lt;/a&gt; module on CPAN describes an abstraction layer around various mechanisms that might be employed to talk to real hardware. It&#38;#39;s still in its early phases yet so it doesn&#38;#39;t have too many actual implementations, but it does support these two hardware boards. It exposes in each case an interface called a GPIO adapter (a &#38;quot;General Purpose Input/Output&#38;quot; - the most basic form of digital IO pin control), which allows us to directly control the high or low state of these pins.&lt;/p&gt;

&lt;p&gt;Using this module we can obtain a object that represents the GPIO ability of the hardware and use the &lt;code&gt;write_gpios()&lt;/code&gt; method on it to set the state of each GPIO pin. As a little technicality, because the &lt;code&gt;Device::Chip&lt;/code&gt; distribution uses &lt;a href=&#34;https://metacpan.org/module/Future&#34;&gt;Future&lt;/a&gt; to make it possible to use asynchronously we&#38;#39;ll just have to call the &lt;code&gt;get()&lt;/code&gt; method on the Future returned by &lt;code&gt;write_gpios()&lt;/code&gt; to actually force it to run. We&#38;#39;ll also have to make sure to use names of the GPIO pins that the particular device will recognise.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# Convert names of our strings of lights to GPIO pin names on&lt;br /&gt;# the adapter&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%CHAIN_TO_GPIO&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;   # If we&#39;re using the FT232H&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;A&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;D0&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;B&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;D1&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;C&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;D2&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;D&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;D3&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;   # If we&#39;re using the Bus Pirate&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;A&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MISO&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;B&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;CS&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;C&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MOSI&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;D&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;CLK&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;set_lights&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$pattern&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;   # $pattern says what light chains to turn on; we&#39;ll also&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;# have to turn the others off&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%want_chains&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( A B C D )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$want_chains&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;split&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$pattern&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;   # Now convert to the pin names required by Device::Chip&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%gpios&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHAIN_TO_GPIO&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$want_chains&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%want_chains&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$gpio&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;write_gpios&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;%gpios&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All we need now to make our program complete is to initialise this &lt;code&gt;$gpio&lt;/code&gt; object at the beginning by opening the actual hardware object. This too comes from &lt;code&gt;Device::Chip&lt;/code&gt; using the handy utility constructor on the &lt;a href=&#34;https://metacpan.org/module/Device::Chip::Adapter&#34;&gt;Device::Chip::Adapter&lt;/a&gt; class called &lt;code&gt;new_from_description()&lt;/code&gt; to first obtain an object representing the hardware adapter itself, and then calling its &lt;code&gt;make_protocol()&lt;/code&gt; method to switch it into GPIO mode and obtain an object specifically representing that.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Device::Chip::Adapter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$adapter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Device::Chip::Adapter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new_from_description&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;FTDI&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;comment&#34;&gt;# Or BusPirate, or whatever...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$gpio&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$adapter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;make_protocol&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;GPIO&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;The-Hardware&#34;&gt;The Hardware&lt;/h3&gt;

&lt;p&gt;Now we&#38;#39;ve got a method of controlling these digital IO lines from perl we can now consider how to actually attach to the actual light chains to it. These IO lines are only capable of controlling 3.3V or 5V up to about 20mA or so; nowhere near enough for some lights. &#38;quot;Low voltage&#38;quot; lights are likely 12 or 24V, and mains ones will run at either 230V or 110V, depending on local supply.&lt;/p&gt;

&lt;p&gt;To do this we&#38;#39;ll need some kind of adapting interface between the digital IO line and the light chain. For a low voltage chain of moderate current (such as a string of LEDs) we can probably use a single NPN transistor along with current-limiting resistor on the base:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;advent-f1.png&#34; width=&#34;284&#34; height=&#34;331&#34;/&gt;&lt;/center&gt;

&lt;p&gt;When the digital IO line is high it drives a current through the transistor (Q1) to ground which allows the transistor to conduct a larger current through the lamp chain, making it light up. When the line is low the base current stops and so the lamp chain goes off.&lt;/p&gt;

&lt;p&gt;There&#38;#39;s a limit to how much current we can switch using this arrangement though - any transistor acts much like a current multiplier; allowing a collector-emitter current to flow that is some multiple of the base-emitter current (usually of the order of 50 times as much). Because the digital IO line on our controller is probably only capable of 20mA or so, that limits our ability to switch lamps up to about 1A.&lt;/p&gt;

&lt;p&gt;To achieve a higher current (perhaps because we have low-voltage incandescent bulbes) we&#38;#39;d likely want to use a pair of transistors in a Darlington arrangement. This arrangement has the effect of multiplying the current up twice - once through each transistor - meaning we could switch a much larger current; maybe up to 10A or so. This should be adequate most low-voltage lamps.&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;advent-f2.png&#34; width=&#34;356&#34; height=&#34;347&#34;/&gt;&lt;/center&gt;

&lt;p&gt;These solutions will only work for low-voltage DC switching, not mains power. For mains-power switching you might consider using a relay, though they tend not to cope so well with faster switching such as required by these kinds of lights. The easiest and safest way to switch a mains-voltage but fairly low-current load is to use an opto-isolated triac. A full discussion of those is probably beyond the scope of this little article, but if you want to read more about that I&#38;#39;d suggest looking up &#38;quot;Arduino isolated triac&#38;quot;, or other variants on that theme. Any sort of Arduino-related article is likely to be fairly relevant, being just digital IO switching at 3.3V or 5V; much as you&#38;#39;d get from these control boards presented above.&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Device::Chip&#34;&gt;Device::Chip&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Device::Chip::Adapter&#34;&gt;Device::Chip::Adapter&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.adafruit.com/products/2264&#34;&gt;FT232H on AdaFruit&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://dangerousprototypes.com/docs/Bus_Pirate&#34;&gt;The Bus Pirate&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-24T00:00:00Z</updated><category term="Perl"/><author><name>Paul &#34;LeoNerd&#34; Evans</name></author></entry><entry><title>Escaping the Basement For Christmas</title><link href="http://perladvent.org/2015/2015-12-23.html"/><id>http://perladvent.org/2015/2015-12-23.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;The Christmas Party on the fourth floor of Reynholm Industries was in full swing. It was the party legends would be made of, something that would be talked about around the water cooler for years to come. Anyone who wasn&#38;#39;t there was sorely missing out. And right now Roy was certainly missing out.&lt;/p&gt;

&lt;p&gt;At his desk in the IT department in the basement, Roy stared at his computer screen in dismay at the endless support requests that kept coming in on Slack. Moss was out at some sort of Countdown related Christmas party, and no-one had seen Richmond since he left for that job as a zoo keeper, leaving his boss Jen the choice between going to the office party or making Roy stay behind and answer support queries...she&#38;#39;d obviously chosen the latter option. And now Roy was forced to endure things like this all evening long:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;ri1.jpg&#34; width=&#34;867&#34; height=&#34;672&#34;&gt;&lt;/center&gt;

&lt;p&gt;If only there was some way he could automate all of this so he could go upstairs and join the frivolity?&lt;/p&gt;

&lt;h3 id=&#34;Slacks-API&#34;&gt;Slack&#38;#39;s API&lt;/h3&gt;

&lt;p&gt;Slack has a fully featured customer accessible API that is able to do pretty much anything Roy could do in the web client. In addition to a collection of normal HTTP GET / PUT / POST API calls Slack supports a websocket API to allow the program to retrieve and answer messages in real time just like the web client does.&lt;/p&gt;

&lt;p&gt;The normal way to use the rtm &lt;i&gt;real time message&lt;/i&gt; service is:&lt;/p&gt;

&lt;ol&gt;
      &lt;li&gt;Make a standard HTTP GET call to the &lt;code&gt;rtm.start&lt;/code&gt; API method to get a unique websocket URL&lt;/li&gt;
      &lt;li&gt;Connect to that bi-directional websocket URL&lt;/li&gt;
      &lt;li&gt;Read JSON from / send JSON to that websocket to receive and send messages respectivly&lt;/li&gt;
    &lt;/ol&gt;

&lt;p&gt;Handling asynchronous programming where your code is both listening and sending messages at the same time used to be complex, but now Perl has a bunch of really good event loop modules that abstract all this away.&lt;/p&gt;

&lt;p&gt;One such framework, Mojolicious, has excellent websocket handling right out of the box, supporting all the idiosyncrasies of connecting to the socket, handling the necessary HTTP socket upgrades specified in the protocols, and allows Roy to simply register callbacks that are triggered whenever the server has sent us a complete chunk of JSON down the socket.&lt;/p&gt;

&lt;p&gt;Given all of this, it shouldn&#38;#39;t be too hard for Roy to use it to write something with it to pretend to be him in Perl:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/perl&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;5.022&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;feature&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(signatures)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;no&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(experimental::signatures)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Mojo::UserAgent&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# The per-user token is availble to logged-in users from the slack website&lt;br /&gt;# to authenticate API users as them.  See https://api.slack.com/web&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$TOKEN&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;xoxp-3234159231-8529214522-1345812313-143531&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ua&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Mojo::UserAgent&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Use the standard synchronous HTTP API get a websocket URL to connect to&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rtm_ws_url&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ua&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;https://slack.com/api/rtm.start&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;form&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;token&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$TOKEN&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;success&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Can&#39;t connect!&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# connect to the websocket&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rtm_start&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$url&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$id&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # connect to the websocket URL asynchronously and then call callback&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ua&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;websocket&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$url&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$ua&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;WebSocket handshake failed!&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;is_websocket&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # handle JSON messages sent to us from the server&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;json&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$msg&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # keep pinging every five seconds to not get disconnected&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;Mojo::IOLoop&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;recurring&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;json&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$id&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;++,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;ping&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$url&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rtm_ws_url&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;rtm_start&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$url&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;Mojo::IOLoop&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Mojo::IOLoop&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;is_running&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With the basics of connecting to the server (and staying connected by sending a ping every five seconds no matter what) done Roy needed to work out how to handle messages sent from the server. Slack sends all kinds of messages: people leaving or joining channels, ping responses, even notifications that people are starting to type. But in reality there was only one message Roy was interested in...someone starting to chat to him in a private one-on-one chat, presumably seeking support. He decided to script his standard one-line response to the first time anyone ever asked him anything that seemed to solve almost every problem that came his way:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# handle JSON messages sent to us from the server&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;json&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;prototype&#34;&gt;($tx,$msg)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # ignore anything but actual messages&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$msg&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;message&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # ignore anything but direct messages&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$channel&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$msg&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;channel&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$channel&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;amp;&#38;amp;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$channel&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/\AD/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # don&#39;t speak twice&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%already_replied&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$already_replied&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$channel&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$already_replied&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$channel&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;json&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$id&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;++,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;message&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;channel&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$channel&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Have you tried turning it off and on again?&#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}});&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Roy didn&#38;#39;t have to wait long before someone triggered his script:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;ri2.jpg&#34; width=&#34;856&#34; height=&#34;667&#34;&gt;&lt;/center&gt;

&lt;p&gt;It worked! Roy ran gleefully upstairs to see if there was any eggnog left.&lt;/p&gt;

&lt;h3 id=&#34;Hey-You-Fix-My-Computer&#34;&gt;Hey You $#%! Fix My Computer!&lt;/h3&gt;

&lt;p&gt;Jen didn&#38;#39;t seem to appreciate his clever solution when he bumped into her next to the punch bowl. She thought it would make people very angry. Normally Roy didn&#38;#39;t listen to Jen too much, but he had to admit that she might be right about that. Maybe he should have the script let him know if someone was truly upset?&lt;/p&gt;

&lt;p&gt;Roy figured if they were swearing at him, he&#38;#39;d better pay attention!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# handle JSON messages sent to us from the server&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;json&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;prototype&#34;&gt;($tx,$msg)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Regexp::Common&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(RE_profanity)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$msg&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;RE_profanity&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;json&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$id&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;++,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;message&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;channel&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$channel&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Hold on, I&#39;m looking into it&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}});&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;notify&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;CODE RED ROY! YOU NEED TO DEAL WITH THIS!&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now when the boss man complained, he should be tempoarly soothed while his script could summon him.&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;ri3.jpg&#34; width=&#34;883&#34; height=&#34;691&#34;&gt;&lt;/center&gt;

&lt;p&gt;All that was needed was some way to notify himself. Of course! The Slack app on his mobile phone could be configured to buzz whenever a particular user - like slackbot, the Slack bot - messaged him. Now all he had to do was lookup the secret slackbot URL for his account on the Slack web pages and make asynchronous posts to that whenever he wanted to notify himself.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$SLACKBOT_URL&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;https://reynholm-industries.slack.com/services/hooks/slackbot&#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;?token=hWa13Ndj32Ajoz2jnaoqu42X&#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#38;amp;channel=%23roytrenneman&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;notify&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($message)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # send non-blocking post&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ua&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;build_tx&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;POST&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$SLACKBOT_URL&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$message&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$ua&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{});&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If he could just avoid drinking enough to lose his phone all would be great!&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Mojo::UserAgent&#34;&gt;Mojo::UserAgent&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Mojo::IOLoop&#34;&gt;Mojo::IOLoop&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Regexp::Common&#34;&gt;Regexp::Common&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-23T00:00:00Z</updated><category term="Perl"/><author><name>Mark Fowler</name></author></entry><entry><title>Automate Christmas with Ansible and Perl</title><link href="http://perladvent.org/2015/2015-12-22.html"/><id>http://perladvent.org/2015/2015-12-22.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Ansible is a pretty great way to version control your infrastructure. It has powerful orchestration features that let you execute plays across any number of servers, and it works through SSH, so in most cases no setup is needed on the client. It comes with a wide range of modules that lets you handle most cases out of the box, like template generation for files, comprehensive rsync support, and even more advanced modules like the most common load balancers and network devices.&lt;/p&gt;

&lt;p&gt;Sometimes there&#38;#39;s a piece in your infrastructure that you just can&#38;#39;t handle with the built in modules like shell or get_url. Luckily it&#38;#39;s easy to write your own modules, and bundle them with your playbooks. As Ansible is written in Python, it&#38;#39;s a common choice, but you can write them in basically anything that can generate a JSON response.&lt;/p&gt;

&lt;p&gt;I&#38;#39;ve written a helper module called &lt;a href=&#34;https://metacpan.org/module/AnsibleModule&#34;&gt;AnsibleModule&lt;/a&gt; that brings the same convenience to Perl that Ansible provides to Python for writing modules, including input validation, automatic response handling, and fatpacking our module.&lt;/p&gt;

&lt;p&gt;Santa Claus inc are heavy users of the Cisco ACE load balancers, which are not supported out of the box in Ansible. During operations they often need to temporarily take one node out of the load balancer to do upgrades, so that every child gets their packages. Let&#38;#39;s look at how we can write a module to help us with that.&lt;/p&gt;

&lt;p&gt;First, let&#38;#39;s install AnsibleModule from CPAN:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ cpanm AnsibleModule&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, let&#38;#39;s start the source code of our project. I tend to keep them in the library/ folder of my playbooks repo. Ansible will automatically look there when you&#38;#39;re running jobs. Let&#38;#39;s make a ace_rserver.pl script now, with the basic code needed:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/env perl&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;AnsibleModule&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;AnsibleModule&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;argument_spec&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;rserver&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;enabled&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;default&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;yes&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;exit_json&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;wheeee&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Make sure it&#38;#39;s executable, and we can test it with the ansible-perl script shipped with AnsibleModule:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ ansible-perl -m library/ace_rserver.pl
  Output from library/ace_rserver.pl: {
    &#38;quot;failed&#38;quot; =&#38;gt; 1,
    &#38;quot;msg&#38;quot; =&#38;gt; &#38;quot;missing required arguments: rserver&#38;quot;
  }
  Response code: 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Seems that argument validation is working, now let&#38;#39;s try again with that argument included&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ ansible-perl -m library/ace_rserver -a &#38;#39;{&#38;quot;rserver&#38;quot;:&#38;quot;test&#38;quot;}&#38;#39;
  Output from library/ace_rserver.pl: {
    &#38;quot;changed&#38;quot; =&#38;gt; 0,
    &#38;quot;msg&#38;quot; =&#38;gt; &#38;quot;wheeee&#38;quot;
  }
  Response code: 0&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pretty good, but ideally you would like to use this with Ansible as well. Of course modules are uploaded and run remotely on each host, so you need to have any perl module you use available on the remote host. Luckily there&#38;#39;s a module called &#38;#39;App::Fatpacker&#38;#39; that can package up your dependencies into one file. ansible-perl can use this to package up your script for you like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ ansible-perl -m library/ace_rserver -p
  Wrote library/ace_rserver.packed&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now you can easily run it on a any host with a recent Perl. Lets test it with the ad hoc ansible command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ ansible -i&#38;#39;localhost local_connection,&#38;#39; -m ace_rserver.packed -a &#38;#39;rserver=foo&#38;#39; localhost
  localhost | success &#38;gt;&#38;gt; {
      &#38;quot;changed&#38;quot;: 0,
      &#38;quot;msg&#38;quot;: &#38;quot;wheeee&#38;quot;
  }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pretty spiffy! Btw, note that you also need to pack it because it includes the WANT_JSON magic keyword in your module. If you want to use it unpacked, you have to include this yourself.&lt;/p&gt;

&lt;p&gt;But our Ansible module isn&#38;#39;t doing very much useful yet. I already created a quick script to test the https interface of the ACE:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/env perl&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Mojo::UserAgent&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;IO::Prompter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$passwd&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;prompt&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Enter your password: &#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-echo&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ua&lt;/span&gt;       &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Mojo::UserAgent&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@commands&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;conf t&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;rserver host test3&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ip address 10.10.11.11&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;end&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;show run&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$command&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#38;lt;request_raw&#38;gt;&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@commands&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#38;lt;/request_raw&#38;gt;&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ua&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;post&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;https://$ENV{USER}:$passwd\@mrom-ip/bin/xml_agent&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;form&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;xml_cmd&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$command&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;success&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;warn&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Got &#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$err&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$err-&#38;gt;{code} response: $err-&#38;gt;{message}&#38;quot;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$err&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;code&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Connection error: $err-&#38;gt;{message}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Integrating that into our Ansible module shouldn&#38;#39;t be too hard. We need a little different arguments. Also let&#38;#39;s turn on support for check mode (if it&#38;#39;s not enabled, Docker will just skip this module in check mode.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;AnsibleModule&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;argument_spec&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;rserver&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;enabled&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;bool&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;yes&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;ace_host&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;ace_user&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;ace_pass&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;supports_check_mode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;First, let&#38;#39;s do a quick sub to run a sequence of raw command and return the output:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;_ace_command&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@commands&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;       &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ua&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;post&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;https://$ENV{ACE_USER}:$ENV{ACE_PASS}\@ENV{ACE_HOST}/bin/xml_agent&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;form&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;xml_cmd&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#38;lt;request_raw&#38;gt;&#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@commands&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#38;lt;/request_raw&#38;gt;&#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;success&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;dom&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;at&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;xml_show_result&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Sorry about the golang-style error-handling scheme. :) Now we can easily use this to check that our rserver exists:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$err&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;_ace_command&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;show run rserver $rserver&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;fail_json&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Could not talk to ACE: $err-&#38;gt;{message} ($err-&#38;gt;{code})&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$err&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;fail_json&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;rserver $rserver not found&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/rserver host $rserver/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then continue to execute the changes specified in the arguments:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;enabled&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;exit_json&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;changed&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/\binservice\b/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$err&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;_ace_command&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;conf t&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;rserver host $rserver&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;no inservice&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39; end&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;double&#34;&gt;&#38;quot;show run rserver $rserver&#38;quot;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;fail_json&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Could not talk to ACE: $err-&#38;gt;{message} ($err-&#38;gt;{code})&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$err&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;fail_json&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Could not take $rserver out of service&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$res&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/\binservice\b/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;exit_json&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;changed&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that AnsibleModule automatically handles trueish/falseish values for your bools in the same fashion as the official Ansible modules. You can just treat them as normal Perlish values. fail_json will automatically stop processing, and return the relevant json struct to Ansible. note the changed value for exit_json; Of course, the else condition is just the reverse of this, I&#38;#39;ll leave that as an exercise for you to figure out. We forgot something though. Earlier, we turned on support for check mode in the constructor. To support this, just wrap the ace_command line and error handling in a conditional.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$module&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;check_mode&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And everything should work as expected. And that should be everything we need. Have fun writing your own Ansible modules, and if you have any trouble or ideas for improvements issues, and especially pull-requests are appreciated at the &lt;a href=&#34;https://github.com/marcusramberg/AnsibleModule)&#34;&gt;github repo&lt;/a&gt;&lt;/p&gt;

&lt;/div&gt;</summary><updated>2015-12-22T00:00:00Z</updated><category term="Perl"/><author><name>Marcus Ramberg</name></author></entry><entry><title>The Perl of Christmas Future </title><link href="http://perladvent.org/2015/2015-12-21.html"/><id>http://perladvent.org/2015/2015-12-21.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Rather being like the fabled Ebenezer Scrooge, staring into his own grave of Christmas Future, Perl 5 is an evolving language giving back to its loved ones every yearly release. Perl 5&#38;#39;s Christmas Future is more like the reformed Ebenezer visiting the Cratchit household, giving out the gifts of new core language features to all and sundry.&lt;/p&gt;

&lt;p&gt;The majority of these new features aren&#38;#39;t available in Perl by default (to preserve backwards compatibility), but can be easily enabled for any section of code by using the &lt;code&gt;feature&lt;/code&gt; keyword. Latest releases of perl even ship with many experimental features that give us a glance of Perl-yet-to-come!&lt;/p&gt;

&lt;h3 id=&#34;Beyond-Modern-Perl&#34;&gt;Beyond Modern Perl&lt;/h3&gt;

&lt;p&gt;Here&#38;#39;s some old-school code written to work on any Perl:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sled&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;pack_naughty_coal&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$packer&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$driver&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$SANTA&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$sled&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;||=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sled&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$person&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;naughty_list&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;      # never load coal for the driver even if they&#39;re on the list!&lt;br /&gt;&lt;/span&gt;      &lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$person&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/\A\Q$driver\E\z/i&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;STDERR&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Loading coal for &#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$person&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$packer&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;pack_coal_for&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$person&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sled&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By enabling the right features in Perl we can turn the above code into the much more readable futuristic Perl:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;pack_naughty_coal&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($self, $packer, $driver = $SANTA)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sled&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sled&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$person&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;naughty_list&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@*&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;      # never load coal for the driver even if they&#39;re on the list!&lt;br /&gt;&lt;/span&gt;      &lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;fc&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$person&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;fc&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$driver&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;STDERR&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Loading coal for &#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$person&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$packer&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;pack_coal_for&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$person&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$sled&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This uses five of the thirteen optional features available in Perl 5.22&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;The &lt;code&gt;state&lt;/code&gt; feature&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;fc&lt;/code&gt; feature&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;say&lt;/code&gt; feature&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;signatures&lt;/code&gt; feature (still &lt;i&gt;experimental&lt;/i&gt; in 5.22)&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;postderef&lt;/code&gt; feature (still &lt;i&gt;experimental&lt;/i&gt; in 5.22)&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;Enabling-Features&#34;&gt;Enabling Features&lt;/h3&gt;

&lt;p&gt;New features in Perl can be enabled in your code one of three ways:&lt;/p&gt;

&lt;dl&gt;

&lt;dt&gt;By explicitly turning them on&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;You can explicitly turn on the features you want for lexical scope with the &lt;code&gt;feature&lt;/code&gt; pragma.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;feature&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;say&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Merry Christmas&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you use an experimental feature you&#38;#39;ll probably want to disable the warnings for that also:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;feature&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;signatures&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;no&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;experimental::signatures&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ask_santa_for&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$wish&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or, preferably, just use the &lt;code&gt;experimental&lt;/code&gt; pragma:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;experimental&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;signatures&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ask_santa_for&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$wish&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However, you should be aware that experimental features are just that - they can change without notice, and if they do...you&#38;#39;ve got no-one to blame but yourself! The future isn&#38;#39;t here yet, after all.&lt;/p&gt;

&lt;/dd&gt;
&lt;dt&gt;By requiring a version of Perl&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;Instead of explicitly stating the feature that you want to use, you can enable for the current lexical scope all the non experimental features supported by a particular version of Perl by requiring a particular version of Perl:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;5.022&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Merry Christmas&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(For 5.12 and later, this will also turn on &lt;code&gt;strict&lt;/code&gt;!)&lt;/p&gt;

&lt;/dd&gt;
&lt;dt&gt;By using &lt;code&gt;-E&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;Using &lt;code&gt;-E&lt;/code&gt; at the command line will turn on all the non-experimental features for the version of Perl that&#38;#39;s executing the script:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   perl -E &#38;#39;say &#38;quot;Merry Christmas&#38;quot;;&#38;#39; &lt;/code&gt;&lt;/pre&gt;

&lt;/dd&gt;
&lt;/dl&gt;

&lt;h3 id=&#34;Looking-At-The-Experimental-Features-Used-In-The-Example&#34;&gt;Looking At The Experimental Features Used In The Example&lt;/h3&gt;

&lt;p&gt;These descriptions are accurate as of 5.22, but by the very nature of experimental features the functionality might have changed if you&#38;#39;re reading this article in the distant future (Enjoy your flying cars and melted ice caps.)&lt;/p&gt;

&lt;h4 id=&#34;The-signature-feature&#34;&gt;The &#38;#39;signature&#38;#39; feature&lt;/h4&gt;

&lt;p&gt;My favorite feature so far, subroutine signatures, is a feature that allow us to avoid having to write explicit code to extract arguments from &lt;code&gt;@_&lt;/code&gt;. Instead, as is common in many other languages, you can simply write an argument list next to the subroutine declaration! This means this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;give&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$person&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$gift&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Can be more compactly written as:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;give&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($person,$gift)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Under the hood Perl builds the necessary instructions as if we&#38;#39;d written the code to do the argument manipulation and checking ourselves manually. If we deparse the compiled source code we can actually see the equivalent code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   shell$ perl -Mfeature=signatures -MO=Deparse -e &#38;#39;sub give($person,$gift) { return 1 }&#38;#39;
   The signatures feature is experimental at -e line 1.
   sub give {
       use feature &#38;#39;signatures&#38;#39;;
       die sprintf(&#38;quot;Too many arguments for subroutine at %s line %d.\n&#38;quot;, (caller)[1, 2]) unless @_ &#38;lt;= 2;
       die sprintf(&#38;quot;Too few arguments for subroutine at %s line %d.\n&#38;quot;, (caller)[1, 2]) unless @_ &#38;gt;= 2;
       my $person = $_[0];
       my $gift = $_[1];
       ();
       return 1;
   }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Perl signatures have a bunch of really clever tricks, including being able to use &lt;i&gt;slurpy&lt;/i&gt; operators to put a variable number of arguments into an array:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;prep_sleigh&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($sled, @reindeer)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;prep_sleigh&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;BigRed2000&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;Dasher&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;Dancer&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;Prancer&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;Vixen&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;Comet&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;Cupid&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;Dunder&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;Blixem&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;They also allow you to specify hashes in the argument list (which will error if a non even number of things are passed in):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;bake_cookies&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;(%args)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;bake_cookies&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;number&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;chocolate&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;icing&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Subroutine signatures allow you to use placeholder unnamed arguments that you want to allow to be passed in without error but don&#38;#39;t actually want to do anything with (I find this very handy when writing methods / callbacks being called from code you didn&#38;#39;t write that may be updated to have extra arguments later)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$delivery_callback&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($address, $status, @)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$status&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$log&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Presents delivered to $address\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$log&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;WARNING: Presents could not be delivered to $address&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One of the most advanced features currently supported is default values; If the argument isn&#38;#39;t passed then the default is used:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;leave_food_for_santa&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($where, $what = $MINCE_PIES)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can even put arbitrary code in there to do whatever you want, for example picking a default at random:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;leave_food_for_santa&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($where, $what = rand() &#38;gt; 0.5 ? $MINCE_PIES : $XMAS_PUDDING)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;Postfix-Dereferencing-the-postderef-feature&#34;&gt;Postfix Dereferencing, the &lt;code&gt;postderef&lt;/code&gt; feature&lt;/h4&gt;

&lt;p&gt;The standard &lt;code&gt;@{ ... }&lt;/code&gt; array dereferencing syntax &lt;i&gt;surrounds&lt;/i&gt; the array reference that it dereferences. This works pretty well for small values:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$arrayref&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[];&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@array&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$arrayref&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or even for slightly more complex things:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$thingy&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;thingy_that_returns_an_arrayref&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But it can get pretty darn hairy where the thing you&#38;#39;re surrounding gets very long.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@shows&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;TV::Schedule&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;subscribed&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;search&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;show&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;My Little Pony: Friendship is Magic&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;Christmas Special&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By the time you get down to reading the closing &lt;code&gt;}&lt;/code&gt; you&#38;#39;ve forgotten what it was for! This can be written a lot clearer with the &lt;code&gt;@*&lt;/code&gt; array dereferencing syntax.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@shows&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;TV::Schedule&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;subscribed&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;search&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;show&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;My Little Pony: Friendship is Magic&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;Christmas Special&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@*&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also do something similar with hashrefs! Instead of writing:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;drive_deer&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($self)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;On $_!&#38;quot;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sort&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;sled&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;deer_team&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;details_hashrefs&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can simply write:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;drive_deer&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($self)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;On $_!&#38;quot;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sort&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;sled&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;deer_team&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;details_hashrefs&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;%*&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want to use postfix dereferencing in a double-quoted string, you should also use the &lt;code&gt;postderef_qq&lt;/code&gt; feature:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;All my present: $gifts_for{me}-&#38;gt;@*&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Both of these get turned on by &lt;code&gt;use experimental &#38;#39;postderef&#38;#39;&lt;/code&gt;, and they&#38;#39;ll be out of experimental status in the upcoming v5.24.0 release!&lt;/p&gt;

&lt;h3 id=&#34;Standard-Features-Used-In-The-Example&#34;&gt;Standard Features Used In The Example&lt;/h3&gt;

&lt;p&gt;I also took advantage of a bunch of non-experimental features in Perl. If you&#38;#39;re writing Perl code for a known version of Perl, you pretty much should be using these as default now.&lt;/p&gt;

&lt;h4 id=&#34;The-say-Feature&#34;&gt;The &lt;code&gt;say&lt;/code&gt; Feature&lt;/h4&gt;

&lt;p&gt;Available since Perl 5.10, the &lt;code&gt;say&lt;/code&gt; keyword is equivalent to the &lt;code&gt;print&lt;/code&gt; keyword with a newline automatically appended. Thus instead of writing:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;STDERR&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Loading coal for &#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$kid&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can just write:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;STDERR&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Loading coal for &#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$kid&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;The-state-Feature&#34;&gt;The &lt;code&gt;state&lt;/code&gt; Feature&lt;/h4&gt;

&lt;p&gt;The state feature introduces a new keyword to declare, &lt;code&gt;state&lt;/code&gt;, that works just like a &lt;code&gt;my&lt;/code&gt; except the code on the right hand side of the expression is only evaluated the first time the line is executed and the variable maintains state every time you re-enter that lexical scope.&lt;/p&gt;

&lt;p&gt;The upshot of this is that things like locally-scoped long-lived variables like counters just got a lot easier to write:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Can be simply rewritten without those annoying extra curly braces:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;The-fc-Feature&#34;&gt;The &lt;code&gt;fc&lt;/code&gt; Feature&lt;/h4&gt;

&lt;p&gt;Doing proper case insensitive comparison of strings is...hard. Sure, it&#38;#39;s easy when you&#38;#39;re only worrying about ASCII characters, but for more advanced character sets where round tripping doesn&#38;#39;t work, you can&#38;#39;t just always &lt;code&gt;uc&lt;/code&gt; or &lt;code&gt;lc&lt;/code&gt; the strings.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# for the kelvin / K characters only lc works&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;lc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;\x{212A}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;lc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;K&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;  &lt;span class=&#34;comment&#34;&gt;# true!&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;uc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;\x{212A}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;uc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;K&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;  &lt;span class=&#34;comment&#34;&gt;# false!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# for sigma / sigma characters only uc works&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;lc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;\x{03C2}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;lc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;\x{03C3}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;  &lt;span class=&#34;comment&#34;&gt;# false!&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;uc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;\x{03C2}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;uc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;\x{03C3}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;  &lt;span class=&#34;comment&#34;&gt;# true!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Rather than a &lt;i&gt;lower case&lt;/i&gt; or &lt;i&gt;upper case&lt;/i&gt; operator we need a &lt;i&gt;folding case&lt;/i&gt; operator that gives us something we can use to compare to see if the strings really are the same case-insensitively. And that operator? It&#38;#39;s &lt;code&gt;fc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;fc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;\x{212A}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;fc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;K&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;         &lt;span class=&#34;comment&#34;&gt;# true!&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;fc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;\x{03C2}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;fc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;\x{03C3}&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;  &lt;span class=&#34;comment&#34;&gt;# true!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;In-Conclusion&#34;&gt;In Conclusion&lt;/h3&gt;

&lt;p&gt;Perl is an evolving language. With the &lt;code&gt;feature&lt;/code&gt; keyword we&#38;#39;re able to bring new standards to scripts while at the same time not requiring that old code be changed to work with the changes if we don&#38;#39;t want it to. With experimental features we&#38;#39;re all able to experiment with cool features in our code today before we make them part of the standard, to become familiar with all the benefits and work out (and hopefully address) the problems before it&#38;#39;s set in stone.&lt;/p&gt;

&lt;p&gt;Speaking from personal experience as someone who recklessly uses all the features I&#38;#39;ve described today while developing production code (including the experimental ones) I&#38;#39;ve found that these little changes add up to make a very big difference in the feel of your code, and greatly improve the development experience. It truly is the Perl of the future.&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/feature&#34;&gt;feature&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://youtu.be/D1LHFKGHceY&#38;amp;t=360&#34;&gt;rjbs YAPC::NA Video on YouTube on Postfix Dereferencing&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://youtu.be/D1LHFKGHceY?t=2341&#34;&gt;rjbs YAPC::NA Video on YouTube on Subroutine Signatures&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://www.effectiveperlprogramming.com/2015/04/use-v5-20-subroutine-signatures/&#34;&gt;http://www.effectiveperlprogramming.com/2015/04/use-v5-20-subroutine-signatures/&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://www.effectiveperlprogramming.com/2014/09/use-postfix-dereferencing/&#34;&gt;http://www.effectiveperlprogramming.com/2014/09/use-postfix-dereferencing/&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://www.effectiveperlprogramming.com/2012/02/fold-cases-properly/&#34;&gt;http://www.effectiveperlprogramming.com/2012/02/fold-cases-properly/&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-21T00:00:00Z</updated><category term="Perl"/><author><name>Mark Fowler</name></author></entry><entry><title>Perl and Redis</title><link href="http://perladvent.org/2015/2015-12-20.html"/><id>http://perladvent.org/2015/2015-12-20.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Redis is high performance in memory key-value-store and data structure server. It runs as a simple daemon alongside your Perl code that you can talk to over the network sending data back and forward for it to persist between invocations and between processes.&lt;/p&gt;

&lt;p&gt;We find that it has affinity with the way we write our application code: We can use Redis variables and data structures as &lt;i&gt;super global variables&lt;/i&gt; that are not only accessible from everywhere in a Perl script but from every process on every server in our infrastructure every time they run. It is very useful and powerful (and dangerous :p).&lt;/p&gt;

&lt;p&gt;These global variables have lots of use, from a simple shared cache, to things like global work queues, process synchronization, or shared leader boards.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    shell$ redis-cli ping
    PONG
    shell$ redis-cli set snowman frosty
    OK
    shell$ redis-cli get snowman
    &#38;quot;frosty&#38;quot;
    shell$ redis-cli lpush gifts gold
    (integer) 1
    shell$ redis-cli lpush gifts frankincense
    (integer) 2
    shell$ redis-cli lpush gifts myrrh
    (integer) 3
    shell$ redis-cli lpop gifts
    &#38;quot;myrrh&#38;quot;
    shell$ redis-cli lpop gifts
    &#38;quot;frankincense&#38;quot;
    shell$ redis-cli lpop gifts
    &#38;quot;gold&#38;quot;
    shell$ redis-cli lpop gifts
    (nil)
    shell$&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&#34;http://redis.io/documentation&#34;&gt;Redis&#38;#39;s documentation&lt;/a&gt; is very full and we can try the commands in &lt;a href=&#34;http://redis.io/commands&#34;&gt;interactive console&lt;/a&gt; in a web browser!&lt;/p&gt;

&lt;p&gt;Let&#38;#39;s introduce the CPAN modules around Redis.&lt;/p&gt;

&lt;h3 id=&#34;Redis&#34;&gt;&lt;a href=&#34;https://metacpan.org/module/Redis&#34;&gt;Redis&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;The original Redis module is a Perl interface to talk to a Redis server:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;incr&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;blah&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis.pm is pure Perl implementation so, stable and easy to understand, but a little bit slow, especially for caching where you don&#38;#39;t want a lot of overhead.&lt;/p&gt;

&lt;h3 id=&#34;Redis::Fast&#34;&gt;&lt;a href=&#34;https://metacpan.org/module/Redis::Fast&#34;&gt;Redis::Fast&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Redis::Fast&#34;&gt;Redis::Fast&lt;/a&gt; is an alternative faster client module for Redis. It has the same Redis.pm interfaces built using XS, so &#38;quot;Fast&#38;quot;. You can use Redis::Fast instead of Redis.pm without making any code changes other than initially instantiating a different object.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis::Fast&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;incr&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;blah&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In my work (online games, SNS and so on), Redis::Fast is also stable and very fast.&lt;/p&gt;

&lt;h3 id=&#34;Cache::Redis&#34;&gt;&lt;a href=&#34;https://metacpan.org/module/Cache::Redis&#34;&gt;Cache::Redis&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Cache::Cache&#34;&gt;Cache::Cache&lt;/a&gt; is a standard caching interface while allows you to easily swap out backend caching technologies - in memory stores, on disk files, memcache, etc - without making changes to your code.&lt;/p&gt;

&lt;p&gt;I wanted to use Redis as caching storage so I wrote a &lt;a href=&#34;https://metacpan.org/module/Cache::Cache&#34;&gt;Cache::Cache&lt;/a&gt; compatible interface client library for Redis called Cache::Redis:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis::Fast&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# you can use Redis.pm too.&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cache&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Cache::Redis&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;redis&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$cache&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;blah&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cache&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;blah&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis also has an interface, &lt;a href=&#34;https://metacpan.org/module/CHI::Driver::Redis&#34;&gt;CHI::Driver::Redis&lt;/a&gt;, to the &lt;a href=&#34;https://metacpan.org/module/CHI&#34;&gt;CHI&lt;/a&gt; caching framework.&lt;/p&gt;

&lt;h3 id=&#34;Redis::LeaderBoard&#34;&gt;&lt;a href=&#34;https://metacpan.org/module/Redis::LeaderBoard&#34;&gt;Redis::LeaderBoard&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Redis not only allows you to store simple key/value pairs on the server, but has a rich API that allows you to manipulate more complex data structures that it can store.&lt;/p&gt;

&lt;p&gt;Redis&#38;#39;s &#38;quot;sorted set&#38;quot; is very useful for creating leaderboards but, which don&#38;#39;t return &#38;quot;unique&#38;quot; rank (cf. &lt;a href=&#34;https://github.com/antirez/redis/issues/943&#34;&gt;https://github.com/antirez/redis/issues/943&lt;/a&gt;&#38;gt;). So I wrote the ranking module using Redis which takes care of &#38;quot;unique&#38;quot; rank.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis::Fast&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis::LeaderBoard&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis::Fast&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lb&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis::LeaderBoard&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;redis&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;key&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;leader_board:1&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;order&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;asc&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# asc/desc, desc as default&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$lb&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;set_score&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;one&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$lb&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;set_score&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;two&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt;  &lt;span class=&#34;number&#34;&gt;50&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$rank&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$score&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lb&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_rank_with_score&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;one&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;#=&#38;gt; (1, 100)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I introduce a technique. That is &#38;quot;using epoch as score&#38;quot;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lb&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis::LeaderBoard&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;redis&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;key&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;recent_post&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;limit&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$lb&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;set_score&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$url&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$updated&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;epoch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# you can get recent posts up to 20 entries&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$recent_posts&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lb&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;rankings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Redis::Namespace&#34;&gt;&lt;a href=&#34;https://metacpan.org/module/Redis::Namespace&#34;&gt;Redis::Namespace&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Generally, key management of a key-value-store is very difficult and confusing (easy to conflict with existing keys used elsewhere in code or other applications using the same Redis server, typo and so on). Key-value-store is very cool, but with this &#38;quot;super global variables store&#38;quot; we must appropriately manage the keys.&lt;/p&gt;

&lt;p&gt;We can use Redis::Namespace for better key name management.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis::Fast&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ns&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Redis::Namespace&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;redis&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$redis&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;namespace&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ranking&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ns&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;bar&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;    &lt;span class=&#34;comment&#34;&gt;# will call $redis-&#38;gt;set(&#39;fugu:foo&#39;, &#39;bar&#39;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$foo&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ns&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;foo&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# will call $redis-&#38;gt;get(&#39;fugu:foo&#39;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The object of Redis::Namespace is to fill up the prefix namespace automatically. I recommend the all Redis objects are wrapped by Redis::Namespace.&lt;/p&gt;

&lt;h3 id=&#34;Conclusion&#34;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;CPAN&#38;#39;s Redis modules allow you to quickly, easily, and safely leverage the power of Redis from Perl.&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Redis&#34;&gt;Redis&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Redis::Fast&#34;&gt;Redis::Fast&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/CHI::Driver::Redis&#34;&gt;CHI::Driver::Redis&lt;/a&gt; and &lt;a href=&#34;https://metacpan.org/module/CHI&#34;&gt;CHI&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Cache::Redis&#34;&gt;Cache::Redis&lt;/a&gt; an &lt;a href=&#34;https://metacpan.org/module/Cache::Cache&#34;&gt;Cache::Cache&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Redis::LeaderBoard&#34;&gt;Redis::LeaderBoard&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Redis::Namespace&#34;&gt;Redis::Namespace&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://redis.io/documentation&#34;&gt;Redis&#38;#39;s documentation&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-20T00:00:00Z</updated><category term="Perl"/><author><name>Masayuki Matsuki</name></author></entry><entry><title>Santa Sorts By Example</title><link href="http://perladvent.org/2015/2015-12-19.html"/><id>http://perladvent.org/2015/2015-12-19.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;For years Santa has resisted the urge to purchase a self-driving sleigh, but the figures published by recent studies have finally convinced him that an autonomous sled might be safer than one being driven by a man who has been up for 24 hours straight. Plus, his also allows him to update this Facebook status without having to worry about colliding with other air traffic.&lt;/p&gt;

&lt;p&gt;Most of the (literal) bells and whistles on the sleigh come pre-configured. The only thing Santa really has to worry about is the order in which his reindeer will line up before the sleigh takes off. (Keep in mind, this sleigh may be self driving, but it&#38;#39;s not electric).&lt;/p&gt;

&lt;p&gt;For years Santa has called out to his reindeer in a very specific order. Perhaps you&#38;#39;re familiar with it? Let&#38;#39;s just confirm the setup. Rudolph (a 20th century addition to the team) leads and lights the way. After that it&#38;#39;s: Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner and Blitzen. There&#38;#39;s some argument over the spelling of the last two names. If in doubt, refer to &lt;a href=&#34;https://en.wikipedia.org/wiki/Santa_Claus%27s_reindeer&#34;&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If any of these reindeer were to take sick, the stand-in reindeer would have to move to the back of the line. After all, if you&#38;#39;ve been doing this for over a century, seniority certainly enters into the picture. In order to ensure that the reindeer are guided in the correct order by the self-driving sleigh, Santa reaches into his bag of tricks and scripts up a little something in Perl. It looks a little like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/env perl;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Data::Printer&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sort::ByExample&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( sbe )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@example&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Rudolph&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dasher&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dancer&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Prancer&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Vixen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Comet&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Cupid&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;single&#34;&gt;&#39;Donner&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Blitzen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sorter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sbe&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@example&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@current_lineup&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Dave&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;single&#34;&gt;&#39;Shirley&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Bubba&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Rudolph&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Vixen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dasher&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Donner&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Zeke&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;single&#34;&gt;&#39;Audrey&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sorted&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sorter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@current_lineup&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;np&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sorted&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This yields the following output:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Rudolph&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Dasher&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Vixen&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Donner&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Dave&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Shirley&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Bubba&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Zeke&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Audrey&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looking at the output we can see that:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;Santa&#38;#39;s reindeer appear first in the list, sorted according to seniority&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Our stand-in reindeer follow in the list, exactly in the order in which they were added to the original list&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So far, so good. Now let&#38;#39;s introduce some secondary sorting. Right now the stand-ins are appearing in the order in which they were originally provided. Let&#38;#39;s sort them alphabetically.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/env perl;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Data::Printer&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sort::ByExample&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( sbe )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@example&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Rudolph&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dasher&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dancer&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Prancer&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Vixen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Comet&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Cupid&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;single&#34;&gt;&#39;Donner&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Blitzen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$fallback&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name_a&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name_b&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name_a&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name_b&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sorter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sbe&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@example&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;fallback&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$fallback&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@current_lineup&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Dave&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;single&#34;&gt;&#39;Shirley&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Bubba&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Rudolph&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Vixen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dasher&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Donner&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Zeke&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;single&#34;&gt;&#39;Audrey&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sorted&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sorter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@current_lineup&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;np&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sorted&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This yields:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Rudolph&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Dasher&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Vixen&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Donner&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Audrey&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Bubba&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Dave&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Shirley&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Zeke&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All we&#38;#39;ve done here is add a very simple fallback subroutine, which dictates a sort order for any scalars which do not appear in the example list.&lt;/p&gt;

&lt;p&gt;Notice that the order of the first four reindeer has not changed, but our stand- ins are now sorted, as we hoped they would be.&lt;/p&gt;

&lt;p&gt;Alphabetical order is kind of arbitrary. What if we wanted to perform the secondary sort according to something more meaningful, like seniority?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/env perl;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Data::Printer&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sort::ByExample&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( sbe )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@example&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Rudolph&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dasher&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dancer&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Prancer&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Vixen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Comet&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Cupid&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;single&#34;&gt;&#39;Donner&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Blitzen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$fallback&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ref_a&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ref_b&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ref_b&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;lt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ref_a&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sorter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sbe&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@example&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;fallback&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$fallback&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;xform&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@current_lineup&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dave&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Shirley&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Bubba&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Rudolph&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Vixen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dasher&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Donner&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;150&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Zeke&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;44&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Audrey&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;44&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sorted&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sorter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@current_lineup&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;np&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sorted&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This yields:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Rudolph&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Dasher&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Vixen&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Donner&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;150&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Zeke&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;44&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Audrey&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;44&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Shirley&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Dave&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Bubba&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What we&#38;#39;ve done here is moved from an array of scalars to an array of hash references, which allows us to use more reindeer metadata. In addition to having a fallback subroutine, we now also have a &lt;code&gt;xform&lt;/code&gt; subroutine. All that &lt;code&gt;xform&lt;/code&gt; does is tell us how to extract the keys which might appear in the &lt;code&gt;@example&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;In addition to this, we&#38;#39;ve now made our &lt;code&gt;fallback&lt;/code&gt; enforce seniority, from highest to lowest.&lt;/p&gt;

&lt;p&gt;Now, what should we do if there&#38;#39;s a tie in seniority, as in the case of Zeke and Audrey? Let&#38;#39;s fall back to alphabetical order in that case.&lt;/p&gt;

&lt;p&gt;That leaves us with:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/env perl;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Data::Printer&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sort::ByExample&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( sbe )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@example&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Rudolph&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dasher&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dancer&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Prancer&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Vixen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Comet&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Cupid&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;single&#34;&gt;&#39;Donner&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Blitzen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$fallback&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name_a&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name_b&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ref_a&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ref_b&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ref_b&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;lt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ref_a&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name_a&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name_b&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sorter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sbe&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@example&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;fallback&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$fallback&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;xform&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@current_lineup&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dave&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Shirley&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Bubba&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Rudolph&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Vixen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Dasher&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Donner&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;150&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Zeke&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;44&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Audrey&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;44&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sorted&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sorter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@current_lineup&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;np&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sorted&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which yields:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Rudolph&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Dasher&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Vixen&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Donner&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;150&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Audrey&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;44&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Zeke&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;44&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Shirley&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Dave&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Bubba&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;seniority&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now in the case of Zeke and Audrey, the tiebreaker kicks in and we&#38;#39;ve got a tertiary sort order.&lt;/p&gt;

&lt;p&gt;That&#38;#39;s it. Now Santa can relax. His reindeer will be queued up in the correct order and his self-driving sleigh will rest assured that it has the correct order in which to call out their names.&lt;/p&gt;

&lt;p&gt;Now, as Santa sits back and enjoys the ride, he thinks of other ways in which he can impose arbitrarily complex sort orders. Perhaps the naughty and nice list is the next logical place?&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Sort::ByExample&#34;&gt;Sort::ByExample&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-19T00:00:00Z</updated><category term="Perl"/><author><name>Olaf Alders</name></author></entry><entry><title>Christmas Wishes</title><link href="http://perladvent.org/2015/2015-12-18.html"/><id>http://perladvent.org/2015/2015-12-18.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;One of the problems with Santa&#38;#39;s delivering presents to all the girls and boys in the world was that when he arrived at midnight in New Zealand to deliver presents to all the good girls and boys, it was twenty three and three quarter hours earlier in Honolulu, barely even Christmas Eve and all the boys and girls there were still making their last minute requests!&lt;/p&gt;

&lt;p&gt;The elves had compensated somewhat by putting extra gifts in Santa&#38;#39;s magic sack of infinite holding, but updating the gift list in real time to tell Santa what everyone wanted was becoming a serious problem: The sat-phone could only transmit so much data, and Santa was getting tired of flying around aimlessly while he waited for the download to complete.&lt;/p&gt;

&lt;h3 id=&#34;The-Problem-With-JSON&#34;&gt;The Problem With JSON&lt;/h3&gt;

&lt;p&gt;Here&#38;#39;s an example update to the gift list the elves needed to send to Santa:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$updates&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;79ABF5D8-9A75-4263-8F8F-A2346EDA62F7&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;wants&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;iPad Pro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Modern Perl 4th Edition&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;7593A066-3C83-4A9C-8A43-4F09D8693B15&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;wants&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Pokemon Alpha-Sapphire&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Modeling Clay&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;2A94FFDB-9FAB-440D-8C2A-D7ED40F30557&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;wants&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;My Two Front Teeth&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Traditionally the elves had been encoding this out with JSON to shoot over the wire.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;JSON::PP&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$bytes&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;encode_json&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$updates&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$bytes&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39; bytes&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This prints &lt;code&gt;268 bytes&lt;/code&gt;. Not so bad, but can the elves do better?&lt;/p&gt;

&lt;h3 id=&#34;Introducing-Sereal&#34;&gt;Introducing Sereal&lt;/h3&gt;

&lt;p&gt;Sereal is &lt;i&gt;an efficient, compact-output, binary and feature-rich serialization protocol&lt;/i&gt;. In other words it&#38;#39;s a standard for bundling up a data structure really small to send over the wire, and is just what the Elves are looking for!&lt;/p&gt;

&lt;h3 id=&#34;Compression&#34;&gt;Compression&lt;/h3&gt;

&lt;p&gt;Sereal has built in compression. Snappy compression should be enough in most situations:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sereal::Encoder&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(encode_sereal SRL_SNAPPY)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$bytes&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;encode_sereal&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$updates&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;compress&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SRL_SNAPPY&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;compress_threshold&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$bytes&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39; bytes&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This prints out the much improved &lt;code&gt;233 bytes&lt;/code&gt;. For better compression we can use Zlib (which is more CPU intensive, but right now the elves need every byte they can get)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sereal::Encoder&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(encode_sereal SRL_ZLIB)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$bytes&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;encode_sereal&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$updates&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;compress&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SRL_ZLIB&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;compress_threshold&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$bytes&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39; bytes&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code prints out the even more improved &lt;code&gt;205 bytes&lt;/code&gt;. Looking at this on a graph we can see we&#38;#39;ve saved just short of quarter of the byte count over using plain old JSON:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;sereal_graph.png&#34; width=&#34;502&#34; height=&#34;312&#34;&gt;&lt;/center&gt;

&lt;h3 id=&#34;Scaling-Up-For-More-Impressive-Results&#34;&gt;Scaling Up For More Impressive Results&lt;/h3&gt;

&lt;p&gt;The elves were concerned about how Sereal would behave when scaling up the size of the data that was being sent - there are a lot of children in the world after all. They decided to re-run the test with a bigger data set. Being thankful to all the CPAN authors in the world Santa decided to give each and every one either new copy of the Modern Perl 4th Edition book or a Round Tuit token:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$updates&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;wants&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.5&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Modern Perl 4th Edition&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;A Round Tuit&#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;E113BD23-E72A-4EC0-A57C-C4E868D9049C&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;7F1AAB0C-4B85-4B42-9C8D-A41C6CF9D93E&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# and 12483 other uuids&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Rerunning the above tests produced an even more impressive savings:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;sereal_graph2.png&#34; width=&#34;482&#34; height=&#34;319&#34;&gt;&lt;/center&gt;

&lt;p&gt;The elves had reduced the byte count by almost 94%!&lt;/p&gt;

&lt;h3 id=&#34;Even-More-Compression&#34;&gt;Even More Compression&lt;/h3&gt;

&lt;p&gt;One of the elves decided to investigate ways to make the data that had to be sent even smaller. Noticing that many of the last minute present requests were for this year&#38;#39;s hot new toy, the elf suggested that the data structure have some short cut code to avoid having to repeat the same string name of the toy over and over again in the data that was sent over the wire.&lt;/p&gt;

&lt;p&gt;Luckily for him, one of the other elves were paying close attention and before he got to work it was pointed out that Sereal can be configured to do this automatically for you!&lt;/p&gt;

&lt;p&gt;The elves tried rerunning the CPAN authors data with the &lt;code&gt;dedupe_strings&lt;/code&gt; option enabled:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$bytes&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;encode_sereal&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$updates&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;compress&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SRL_ZLIB&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;dedupe_strings&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This resulted in even smaller bytesize&lt;/p&gt;

&lt;table class=&#34;pretty-table&#34;&gt;
  &lt;thead&gt;
  &lt;tr&gt;
  &lt;td&gt;dedupe_strings&lt;/td&gt;
  &lt;td&gt;Bytes&lt;/td&gt;
  &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
  &lt;tr class=&#34;alt&#34;&gt;
  &lt;td&gt;disabled&lt;/td&gt;
  &lt;td&gt;60207&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
  &lt;td&gt;enabled&lt;/td&gt;
  &lt;td&gt;58537&lt;/td&gt;
  &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;/table&gt;

&lt;h3 id=&#34;Success&#34;&gt;Success&lt;/h3&gt;

&lt;p&gt;This year not only would the gift list update quicker, Santa&#38;#39;s phone bill would also be considerably less!&lt;/p&gt;

&lt;/div&gt;</summary><updated>2015-12-18T00:00:00Z</updated><category term="Perl"/><author><name>Ivan Kruglov</name></author></entry><entry><title>No More Leaking Glue</title><link href="http://perladvent.org/2015/2015-12-17.html"/><id>http://perladvent.org/2015/2015-12-17.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Perl is often used as a &#38;quot;glue language&#38;quot;. You have a bunch of other programs that you want to automate from one place, so you use Perl. You put the programs carefully in position, grab the bottle of Krazy Glue, drizzle it everywhere, and bask in the glow of what you&#38;#39;ve accomplished.&lt;/p&gt;

&lt;p&gt;Only then, inevitably, you can&#38;#39;t put down the glue bottle. It&#38;#39;s not that you&#38;#39;ve gone mad with a need to automate all the things - although that&#38;#39;s a possibility, too. This time, though, you&#38;#39;ve glued the glue bottle to your hand, and no matter what those people on the GlueGaffes subreddit tell you, the only way to get that bottle off your hands is to become some sort of snake monster and shed your skin. This, presumably, is how Python programmers come to be.&lt;/p&gt;

&lt;p&gt;Well, the abstraction leak in our Perl glue layer might not be so bad, but it&#38;#39;s still a big annoyance. It&#38;#39;s all those places where Perl reminds you, &#38;quot;Hey! Hey! Lots of me is just a little wrapper around C library stuff!&#38;quot; Isn&#38;#39;t that great? This is why you end up with &lt;code&gt;stat&lt;/code&gt; returning a thirteen element list, for example. (Wait, the Perl Advent Calendar has never featured an article on &lt;a href=&#34;https://metacpan.org/module/File::stat&#34;&gt;File::stat&lt;/a&gt;? Well, check it out later, because that&#38;#39;s not the problem we&#38;#39;re talking about right now.)&lt;/p&gt;

&lt;p&gt;Right now the problem we&#38;#39;re talking about is running subprocesses. There are a number of ways to do this; You might use &lt;code&gt;system&lt;/code&gt;. You might use &lt;code&gt;open&lt;/code&gt;. You might use &lt;code&gt;fork&lt;/code&gt;. They all have one thing in common: when the process you started via those means exits, you get its exit status in the same place: &lt;code&gt;$?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$?&lt;/code&gt; (known by devotees of the &lt;a href=&#34;http://www.amazon.com/Perl-Best-Practices-Damian-Conway/dp/0596001738&#34;&gt;Way of the Dog&lt;/a&gt; as &lt;code&gt;$CHILD_STATUS&lt;/code&gt;) is a global variable that gets populated with the numeric status of the ex-process. It&#38;#39;s supposed to be easy to remember &lt;code&gt;$?&lt;/code&gt; because it&#38;#39;s the same name as in shell programming...but in the shell, &lt;code&gt;$?&lt;/code&gt; is the exit value of the program. If a program exits 75, then &lt;code&gt;$?&lt;/code&gt; is 75. In Perl, that would be 19200...and now you just glued your finger to the keyboard.&lt;/p&gt;

&lt;p&gt;Perl is leaking the way that status code is packed into the status integer in C: eight bits of exit value, seven bits of signal identifier, and one bit to flag whether the process dumped core. Instead of giving you three variables, you get one number between 0 and 65535. Great!&lt;/p&gt;

&lt;p&gt;In C, there are macros for getting the data you wanted.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;exit_status = WEXITSTATUS(status);&lt;br /&gt;signal      = WTERMSIG(status);&lt;br /&gt;exit_status = WCOREDUMP(status);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In Perl, you typically find people using bit-shift operators to extract the part of the return code they care about:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;system&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$some_command&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sprintf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;program exited %i&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$?&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;lt;&#38;lt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...which the hardened Perl programmer tends to recognize at a glance (and doesn&#38;#39;t even notice how ridiculous it is to type this all the time).&lt;/p&gt;

&lt;p&gt;Speaking of things even we Perl veterans fail to notice: When the code accidentally uses &lt;code&gt;&#38;lt;&#38;lt;&lt;/code&gt; instead of &lt;code&gt;&#38;gt;&#38;gt;&lt;/code&gt;. Ooops. Did you notice I should have actually written the above code as:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;system&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$some_command&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sprintf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;program exited %i&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$?&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But that&#38;#39;s the problem when you&#38;#39;re using non-obvious syntax. It&#38;#39;s non-obvious! And even when someone does a proper code review they don&#38;#39;t catch that kind of thing.&lt;/p&gt;

&lt;p&gt;We &lt;i&gt;also&lt;/i&gt; also probably don&#38;#39;t catch the situations where we might care about the signal but then we totally forget to check or print it in our code. Why did we fail to do that? Maybe because it was more work, and maybe because we have a quota of one bitwise operation allowed per Perl program per day and we hit it with the first one.&lt;/p&gt;

&lt;p&gt;Of course, we can eliminate these stupid errors with everyone&#38;#39;s favorite core module... POSIX!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# ARGH MY EYES&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;POSIX&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(WEXITSTATUS)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;system&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$some_command&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sprintf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;program exited %i&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;WEXITSTATUS&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$?&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ha ha just kidding. I mean, you &lt;i&gt;could&lt;/i&gt; do that, but then you&#38;#39;d be using POSIX.pm, and you&#38;#39;d have to hold down the shift keys a whole lot when typing, &lt;i&gt;and&lt;/i&gt; you&#38;#39;d have to remember to add that code for signals! Also, seriously, &lt;i&gt;POSIX.pm&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;This is why Process::Status exists. It&#38;#39;s such a useful module that Ruby stole it from us, then travelled back in time 15 years to make it look like they wrote it first.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Process::Status&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;system&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$some_command&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;Process::Status&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;assert_ok&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If your program exited 0, nothing happens. If it exited non-zero, you get an exception like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  program exited 13, caught SIGWOOP; dumped core at line...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are a bunch of other useful methods for finer-grained handling, but for the most part the only three you need to know are self-explanatory:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;as_string&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;assert_ok&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;is_success&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you ever run subprocesses from Perl, use Process::Status.&lt;/p&gt;

&lt;p&gt;If you don&#38;#39;t ever run subprocesses from Perl, I don&#38;#39;t even understand your life.&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Process::Status&#34;&gt;Process::Status&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/File::stat&#34;&gt;File::stat&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/POSIX&#34;&gt;POSIX&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-17T00:00:00Z</updated><category term="Perl"/><author><name>Ricardo SIGNES</name></author></entry><entry><title type="html">Building Santa&#38;#39;s Naughty and Nice List with Stepford</title><link href="http://perladvent.org/2015/2015-12-16.html"/><id>http://perladvent.org/2015/2015-12-16.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;It&#38;#39;s a little known fact that Santa&#38;#39;s elves are the ones responsible for producing his yearly naughty and nice list. But working on the list has been taking up time that they&#38;#39;d rather use for drinking pine juice and playing Dark Souls. They have a crufty &lt;code&gt;Makefile&lt;/code&gt; but it doesn&#38;#39;t do a great job of rebuilding things when dependencies change, so they&#38;#39;re constantly finding output errors and having to delete old files. It also doesn&#38;#39;t play all that nicely with the Perl code they wrote to do the real work.&lt;/p&gt;

&lt;p&gt;So the elves pooled their money and hired me to automate building the list. Looking at how they&#38;#39;d built the list before, I realized that &lt;a href=&#34;https://metacpan.org/release/Stepford&#34;&gt;Stepford&lt;/a&gt; was the perfect tool for the job!&lt;/p&gt;

&lt;h3 id=&#34;What-is-Stepford&#34;&gt;What is Stepford?&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/release/Stepford&#34;&gt;Stepford&lt;/a&gt; is a tool that takes a set of steps (tasks), figures out their dependencies, and then runs them in the right order to get the result that you ask for. The result itself is just another step that you specify when creating the &lt;a href=&#34;https://metacpan.org/pod/Stepford::Runner&#34;&gt;&lt;code&gt;Stepford::Runner&lt;/code&gt;&lt;/a&gt; object. Steps are Perl classes built using &lt;a href=&#34;https://metacpan.org/release/Moose&#34;&gt;&lt;code&gt;Moose&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&#34;Dependencies-and-Productions&#34;&gt;Dependencies and Productions&lt;/h4&gt;

&lt;p&gt;The &#38;quot;big thing&#38;quot; that Stepford does for you is to figure out the dependencies needed to get to the final step. It does this by looking at the dependencies and productions of all your steps and then running those steps in the necessary order.&lt;/p&gt;

&lt;p&gt;Both dependencies and productions are declared as Moose attributes with a special &lt;code&gt;trait&lt;/code&gt;. Here&#38;#39;s an example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;geolite2_database_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;traits&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;StepDependency&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;       &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ip_scores_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;traits&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;StepProduction&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lazy&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;builder&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_build_ip_scores_file&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You&#38;#39;ll see how to actually populate the &lt;code&gt;ip_scores_file&lt;/code&gt; later.&lt;/p&gt;

&lt;p&gt;Stepford matches a production to a dependency solely by name, which means that attribute names for productions and dependencies must be unique to a given set of steps.&lt;/p&gt;

&lt;h4 id=&#34;Step-Classes&#34;&gt;Step Classes&lt;/h4&gt;

&lt;p&gt;A &#38;quot;Step class&#38;quot; is any Moose class which consumes the &lt;a href=&#34;https://metacpan.org/pod/Stepford::Role::Step&#34;&gt;&lt;code&gt;Stepford::Role::Step&lt;/code&gt;&lt;/a&gt; role (or another role which in turn consumes that role). This role in turn requires that a step class implement a few specific methods named &lt;code&gt;run&lt;/code&gt; and &lt;code&gt;last_run_time&lt;/code&gt;. You&#38;#39;ll see examples of both of these methods as we go further.&lt;/p&gt;

&lt;h3 id=&#34;What-Goes-Into-the-Naughty-and-Nice-List&#34;&gt;What Goes Into the Naughty and Nice List?&lt;/h3&gt;

&lt;p&gt;The elves gave me a long list of requirements, but honestly it all seemed like too much trouble. And since these elves are not very technically savvy, I&#38;#39;m going to take the easy route instead and just make some stuff up.&lt;/p&gt;

&lt;p&gt;Here&#38;#39;s what I&#38;#39;m going to do:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;Get the names and IP addresses for all the children in the world, or at least a few of them.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Assign each child a UUID so I can track them easily.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Download the &lt;a href=&#34;http://dev.maxmind.com/geoip/geoip2/geolite2/&#34;&gt;free GeoLite2 database&lt;/a&gt; from MaxMind.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the GeoLite2 database to look at each child&#38;#39;s geographical location and use that to give their IP a naughty/nice score. This will be very scientific.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Look at each child&#38;#39;s name and use that to give their name a naughty/nice score. Again, this will be very scientific.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Combine the IP and name scores into a single score per child and generate a text file with the naughty/nice list.&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&#38;#39;s a graph of each step showing each steps&#38;#39; dependencies:&lt;/p&gt;

&lt;center&gt;&lt;a href=&#34;step-graph.svg&#34;&gt;&lt;img src=&#34;step-graph.svg&#34; height=&#34;450&#34; width=&#34;450&#34;&gt;&lt;/a&gt;&lt;/center&gt;

&lt;p&gt;Looking at this graph, you can see a couple interesting things. First, there are two steps, &#38;quot;Get list of children&#38;quot; and &#38;quot;Download GeoLite2 databases&#38;quot;, with no dependencies. Next, there are steps that are dependencies for more than one other steps, &#38;quot;Assign UUIDs&#38;quot; and &#38;quot;Get list of children&#38;quot;. Finally, the &#38;quot;Combine scores&#38;quot; step has three dependencies but is not a dependency of any other step.&lt;/p&gt;

&lt;p&gt;Figuring all this stuff out is what Stepford is for. In fact, it calculates a graph just like this internally.&lt;/p&gt;

&lt;h3 id=&#34;Building-our-First-Step&#34;&gt;Building our First Step&lt;/h3&gt;

&lt;p&gt;Let&#38;#39;s start by building the step to &#38;quot;Get list of children&#38;quot;. All the step classes for a single set of steps should live under the same namespace. I&#38;#39;m going to use &lt;code&gt;NN::Step&lt;/code&gt; as our namespace prefix.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;NN::Step::Children&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;autodie&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;experimental&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;signatures&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Data::GUID&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MooseX::Types::Path::Class&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( Dir File )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Text::CSV_XS&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Stepford::Role::Step::FileGenerator&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;no&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;experimental::signatures&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;root_dir&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Dir&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;coerce&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;.&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;children_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;traits&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;StepProduction&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lazy&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;builder&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_build_children_file&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;children_file&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;Writing names and IPs to $file&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$data&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;readline&#34;&gt;&#38;lt;DATA&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # CSV line ending per http://tools.ietf.org/html/rfc4180&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;$data&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;substitute&#34;&gt;s/\n/\r\n/g&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;spew&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$data&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;_build_children_file&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;root_dir&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;children.csv&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;__PACKAGE__&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;meta&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;make_immutable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;separator&#34;&gt;__DATA__&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;data&#34;&gt;&#38;quot;Alexander Marer&#38;quot;,42.235.92.147&lt;br /&gt;&#38;quot;Andrew Bernard Cray&#38;quot;,205.145.143.62&lt;br /&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&#38;#39;s look at the interesting bits more closely.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Stepford::Role::Step::FileGenerator&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All Stepford classes must consume one of the Step roles provided by Stepford. This particular role tells Stepford that all of this step&#38;#39;s outputs are in the form of files. This lets Stepford calculate the step&#38;#39;s last run time by looking at the file&#38;#39;s modification time. For non-file steps, you have to provide a &lt;code&gt;last_run_time&lt;/code&gt; method of your own.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;root_dir&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Dir&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;coerce&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;.&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;children_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;traits&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;StepProduction&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lazy&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;builder&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_build_children_file&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This class has two attributes. The &lt;code&gt;root_dir&lt;/code&gt; attribute is neither a dependency nor a production. You&#38;#39;ll see how to set this attribute later on. The &lt;code&gt;children_file&lt;/code&gt; attribute is a production. Some other steps will depend on this production.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;prototype&#34;&gt;($self)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;children_file&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;Writing names and IPs to $file&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$data&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;readline&#34;&gt;&#38;lt;DATA&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # CSV line ending per http://tools.ietf.org/html/rfc4180&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;$data&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;substitute&#34;&gt;s/\n/\r\n/g&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;spew&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$data&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Every Step class must provide a &lt;code&gt;run&lt;/code&gt; method. This method is expected to do whatever work the step does. In this case I take the list of children in &lt;code&gt;DATA&lt;/code&gt; and turn it into a CSV file.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;logger&lt;/code&gt; attribute is provided to each step by the &lt;a href=&#34;https://metacpan.org/pod/Stepford::Runner&#34;&gt;&lt;code&gt;Stepford::Runner&lt;/code&gt;&lt;/a&gt; class. You&#38;#39;ll learn more about that class later.&lt;/p&gt;

&lt;h4 id=&#34;Atomic-File-Steps&#34;&gt;Atomic File Steps&lt;/h4&gt;

&lt;p&gt;I could have used &lt;a href=&#34;https://metacpan.org/pod/Stepford::Role::Step::FileGenerator::Atomic&#34;&gt;&lt;code&gt;Stepford::Role::Step::FileGenerator::Atomic&lt;/code&gt;&lt;/a&gt; instead. If your step is writing a file, using this role will prevent you from leaving behind a half-finished file if the step dies. I didn&#38;#39;t use it in my example code just to keep the code simpler, but I highly recommend it for production code.&lt;/p&gt;

&lt;h3 id=&#34;More-Steps&#34;&gt;More Steps&lt;/h3&gt;

&lt;p&gt;The other steps are pretty similar. They take some data and spit something new out. Let&#38;#39;s take a look at some of the code from the step that adds the UUIDs:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;NN::Step::AssignUUIDs&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;children_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;traits&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;StepDependency&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;       &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;children_with_uuids_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;traits&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;StepProduction&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lazy&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;builder&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_build_children_with_uuids_file&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This step depends on the &lt;code&gt;children_file&lt;/code&gt; created by the &lt;code&gt;Children&lt;/code&gt; step. Stepford will figure this out and make sure that the steps are run in the correct order.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;AssignUUIDs&lt;/code&gt; step in turn has its own &lt;code&gt;StepProduction&lt;/code&gt; which future steps will depend on.&lt;/p&gt;

&lt;p&gt;The remaining steps follow a similar pattern. They take an input file and produce an output file. The last step, &lt;code&gt;WriteList&lt;/code&gt;, is a little different, so let&#38;#39;s see how:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;NN::Step::WriteList&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Stepford::Role::Step&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first difference is that I&#38;#39;m consuming the &lt;a href=&#34;https://metacpan.org/pod/Stepford::Role::Step&#34;&gt;&lt;code&gt;Stepford::Role::Step&lt;/code&gt;&lt;/a&gt; role instead of &lt;a href=&#34;https://metacpan.org/pod/Stepford::Role::Step::FileGenerator&#34;&gt;&lt;code&gt;Stepford::Role::Step::FileGenerator&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is mostly so I can demonstrate how to write a &lt;code&gt;last_run_time&lt;/code&gt; method.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;children_with_uuids_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;traits&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;StepDependency&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;       &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ip_scores_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;traits&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;StepDependency&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;       &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name_scores_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;traits&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;StepDependency&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;       &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This step has three dependencies, unlike the previous steps you&#38;#39;ve seen. Each of these dependencies comes from a separate step. Stepford will figure all that out for us and run those steps before this one.&lt;/p&gt;

&lt;p&gt;And here&#38;#39;s the &lt;code&gt;last_run_time&lt;/code&gt; method:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;last_run_time&lt;/span&gt; &lt;span class=&#34;prototype&#34;&gt;($self)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;_naughty_nice_list&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;-e&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;stat&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;mtime&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is pretty straightforward. If the file exists, I return its last modification time. If not, I return &lt;code&gt;undef&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Stepford uses the value of each step&#38;#39;s &lt;code&gt;last_run_time&lt;/code&gt; to determine whether or not a given step needs to be run at all. If the data in a dependency is newer than the data in the step that depends on that data, there&#38;#39;s no point in regenerating the dependency&#38;#39;s data.&lt;/p&gt;

&lt;p&gt;(By the way, the &lt;code&gt;last_run_time&lt;/code&gt; method above is essentially the same as the one in &lt;code&gt;Stepford::Role::Step::FileGenerator&lt;/code&gt;.)&lt;/p&gt;

&lt;h3 id=&#34;Running-Your-Steps&#34;&gt;Running Your Steps&lt;/h3&gt;

&lt;p&gt;Now that I&#38;#39;ve written my steps, how do I run them? Here&#38;#39;s the script I wrote:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/env perl&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;FindBin&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( $Bin )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;lib&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$Bin/../lib&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Getopt::Long&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Log::Dispatch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Stepford::Runner&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$debug&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$jobs&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$root&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GetOptions&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;debug&#39;&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$debug&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;jobs:i&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$jobs&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;root:s&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$root&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$logger&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Log::Dispatch&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;outputs&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;Screen&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;newline&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;min_level&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$debug&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;debug&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;warning&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;Stepford::Runner&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;step_namespaces&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;NN::Step&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;logger&lt;/span&gt;          &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$root&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;root_dir&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$root&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;final_steps&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;NN::Step::WriteList&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The only interesting piece is my use of &lt;a href=&#34;https://metacpan.org/pod/Stepford::Runner&#34;&gt;&lt;code&gt;Stepford::Runner&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;Stepford::Runner&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;step_namespaces&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;NN::Step&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;logger&lt;/span&gt;          &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;jobs&lt;/span&gt;            &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$jobs&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$root&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;root_dir&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$root&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;final_steps&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;NN::Step::WriteList&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;Stepford::Runner&lt;/code&gt; constructor takes several named arguments. The &lt;code&gt;step_namespaces&lt;/code&gt; argument tells Stepford under what namespace it should look for steps. It will load all the classes that it finds under this namespace.&lt;/p&gt;

&lt;p&gt;You can pass multiple namespaces as an array reference. When two steps have a production of the same name, then the step that comes first in the list of namespaces wins. This is useful for testing, as it lets you mock as many steps as you need to.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;logger&lt;/code&gt; can be any object that provides a certain set of methods (&lt;code&gt;debug&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt;, etc.).&lt;/p&gt;

&lt;p&gt;Finally, if you set &lt;code&gt;jobs&lt;/code&gt; to a value greater than one, Stepford will run steps in parallel, running up to &lt;code&gt;$jobs&lt;/code&gt; steps at once whenever possible.&lt;/p&gt;

&lt;p&gt;The call to the &lt;code&gt;run&lt;/code&gt; method also accepts named arguments. Keys in the &lt;code&gt;config&lt;/code&gt; argument which match constructor arguments for a step will be passed to that step class as the step is constructed. Remember way back up above when I mentioned that I&#38;#39;d show you how to set the &lt;code&gt;root_dir&lt;/code&gt; attribute of the &lt;code&gt;NN::Step::Children&lt;/code&gt; class. This is how you do that.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;final_steps&lt;/code&gt; argument can be a single step class name or an array reference of names. This is how you specify the result you&#38;#39;re asking Stepford for.&lt;/p&gt;

&lt;h3 id=&#34;Why-Stepford&#34;&gt;Why Stepford?&lt;/h3&gt;

&lt;p&gt;Stepford is lot like &lt;code&gt;make&lt;/code&gt;, &lt;code&gt;rake&lt;/code&gt;, and many other tools. Stepford was originally created to help improve our automation around building &lt;a href=&#34;https://www.maxmind.com/en/geoip2-databases&#34;&gt;GeoIP databases&lt;/a&gt; at &lt;a href=&#34;https://www.maxmind.com/&#34;&gt;MaxMind&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I investigated &lt;code&gt;make&lt;/code&gt; and &lt;code&gt;rake&lt;/code&gt;, which are both great tools. However, what makes them shine is how they integrate with certain environments. The &lt;code&gt;make&lt;/code&gt; tool is great if you&#38;#39;re interacting with a lot of existing command line tools like compilers, linkers, etc. And of course &lt;code&gt;rake&lt;/code&gt; is great if you&#38;#39;re dealing with existing Ruby code.&lt;/p&gt;

&lt;p&gt;But our database building code was is written in Perl, so it made sense to write a tool in Perl.&lt;/p&gt;

&lt;p&gt;If you&#38;#39;re in a similar situation, with a Perl code base that executes a series of steps towards one or more final products, then Stepford might be a good choice for you as well.&lt;/p&gt;

&lt;p&gt;It certainly worked well for those elves. Sure, the naughty and nice list they get is complete and utter nonsense, but it&#38;#39;s a lot quicker to generate, giving them more time for their pine juice-fueled Dark Souls speedruns.&lt;/p&gt;

&lt;h3 id=&#34;The-Code&#34;&gt;The Code&lt;/h3&gt;

&lt;p&gt;If you want to see all the step code for this article, check out &lt;a href=&#34;https://github.com/autarch/perl-advent-calendar-2015-stepford&#34;&gt;this article&#38;#39;s GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;See-Also&#34;&gt;See Also&lt;/h3&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/release/Stepford&#34;&gt;Stepford&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.gnu.org/software/make/&#34;&gt;make&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://docs.seattlerb.org/rake/&#34;&gt;rake&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-16T00:00:00Z</updated><category term="Perl"/><author><name>Dave Rolsky</name></author></entry><entry><title>Garlands of YAML and JSON</title><link href="http://perladvent.org/2015/2015-12-15.html"/><id>http://perladvent.org/2015/2015-12-15.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Gluggag&#38;aelig;gir the Elf had to admit that the myriad of IT systems that worked together at the North Pole was amazing. All built different, in different languages, and with different technologies. Luckily, the Elves had decided that everyone should use a universal serialization format so that all the different systems could talk to each other. Unfortunately, however, none of the elves could agree what that should be, and they&#38;#39;d all ended up using a &lt;i&gt;different&lt;/i&gt; universal serialization format.&lt;/p&gt;

&lt;p&gt;While some elves are working at Santa&#38;#39;s Gift Factories for a Holidays season or two before they move to greener pastures (usually quite literally greener, as the Easter Bunny is notoriously known to be the biggest elf poacher around) Gluggag&#38;aelig;gir is one of your long-term commitment type of elf. He&#38;#39;s been around and worked in most departments, and expects to be around longer still, slowly moving up the yuletide ladder until &#38;mdash; who knows? &#38;mdash; he makes it as Cheers Chief Officer.&lt;/p&gt;

&lt;p&gt;So Glugg has made the decision not to argue with the trend du jour, whatever that might be. Why can&#38;#39;t we just accept input in any of the contested serialization formats and have the computer, which is pretty smart at processing data, figure it all out?&lt;/p&gt;

&lt;p&gt;The current hot debate was should the elves be serializing data in either YAML or JSON, both of which are readable and fairly easy to manipulate. Either was perfectly fine with Glugg, as he&#38;#39;s an old-hand to the serialization/deserialization dance. And happens to have one more handy tool on his belt for those tasks: &lt;a href=&#34;https://metacpan.org/module/File::Serialize&#34;&gt;File::Serialize&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;Keep-it-short-keep-it-sweet&#34;&gt;Keep it short, keep it sweet&lt;/h3&gt;

&lt;p&gt;The main raison d&#38;#39;&#38;ecirc;tre of &lt;a href=&#34;https://metacpan.org/module/File::Serialize&#34;&gt;File::Serialize&lt;/a&gt; is to encapsulate and take care of all the boring, repetitive details that come with serialization. Before using File::Serialize, Glugg used to have two scripts that looked like&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;NorthPole::DB&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;YAML&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$nice_children&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;YAML::LoadFile&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;nice.yaml&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;update_db&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;nice&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$nice_children&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;NorthPole::DB&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;JSON&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Path::Tiny&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$naughty_children&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;from_json&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;naughty&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;slurp&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;update_db&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;naughty&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$naughty_children&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In other words, almost the same, except for the serialization engine. But with &lt;a href=&#34;https://metacpan.org/module/File::Serialize&#34;&gt;File::Serialize&lt;/a&gt;, he now can just hide that difference under the blanket:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;NorthPole::DB&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File::Serialize&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;nice&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;nice.yaml&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;naughty&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;naughty.json&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$status&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;each&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%list&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;update_db&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$status&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;deserialize_file&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And it goes the other way around as well. The module can also figure out the right output format and deal with common options (pretty-printing, utf8 output, canonical representation) based on the filename the script is writing to:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;NorthPole::DB&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File::Serialize&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;pretty&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;canonical&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;utf8&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$children&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;query_db&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%report&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;nice&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;nice_out.yaml&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;naughty&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;naughty_out.json&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$status&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;each&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%list&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;serialize_file&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;behavior&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$status&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$children&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;];&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With, of course, always the possibility to explicitly choose a specific format, for those special cases.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# TODO: have a chat with the Teddy Bear division &lt;br /&gt;# about cutesy extensions...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;serialize_file&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;teddy.hohoho&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;want&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;teddy bear&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$nice_children&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;json&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Keep-it-magic-when-you-need-to-be-l33t&#34;&gt;Keep it magic, when you need to be l33t&lt;/h3&gt;

&lt;p&gt;And then there is the module&#38;#39;s carefully guarded little hidden bonus: it also has a function called &lt;code&gt;transerialize_file&lt;/code&gt;, which allows to implement a small pipeline (or, in dev&lt;i&gt;elf&lt;/i&gt;oper lingo, a garland) of transformations. For example, Glugg&#38;#39;s real script is even shorter than the snippets given above, and looks something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;transerialize_file&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;query_db&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;all_children.yml&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;behavior&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;naughty&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;naughty.json&#39;&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;behavior&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;nice&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;nice.json&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;want&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;teddy bear&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;teddy.hohoho&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;json&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Short and efficient. That&#38;#39;s how elves are, and that&#38;#39;s how they like their code to be.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2015-12-15T00:00:00Z</updated><category term="Perl"/><author><name>Yanick Champoux</name></author></entry><entry><title>crash kayo zamm splatt</title><link href="http://perladvent.org/2015/2015-12-14.html"/><id>http://perladvent.org/2015/2015-12-14.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;center&gt;&lt;img src=&#34;pow.png&#34; width=&#34;400&#34; height=&#34;204&#34;&gt;&lt;/center&gt;

&lt;p&gt;Would it shock you to know that despite having created one hundred and fifteen (and counting) Perl Advent Calendar entries over the years, I&#38;#39;ve never written an article on one of the smallest, silliest, modules that I rely on every day? A module that I can&#38;#39;t debug my code without?&lt;/p&gt;

&lt;p&gt;And the name of that module? &lt;b&gt;Acme::MetaSyntactic&lt;/b&gt;. Yes, that&#38;#39;s right. An &lt;i&gt;Acme&lt;/i&gt; module, from the namespace on the CPAN that&#38;#39;s traditionally reserved for joke modules. I&#38;#39;d better explain why I rely so heavily on one of these, shouldn&#38;#39;t I?&lt;/p&gt;

&lt;p&gt;There was a time when, like a chump, I&#38;#39;d write statements like this throughout my code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;STDERR&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Here!\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;STDERR&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Got Here Also!\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This &lt;i&gt;poor man&#38;#39;s debugger&lt;/i&gt; technique is surprisingly effective. Unlike a real debugger it works well with web applications, it doesn&#38;#39;t require an external module support (so in a pinch you can even use it on one of the production servers you&#38;#39;ve temporarily stopped the load balancer sending live traffic to) and can be left unattended to generate output on minutes long scripts while you go and fetch a hot beverage.&lt;/p&gt;

&lt;p&gt;So if this is so effective, why was I a chump for using it? All that &lt;i&gt;typing&lt;/i&gt;. Having to come up with &lt;i&gt;unique new strings&lt;/i&gt; to print out all the time...I can&#38;#39;t tell you the number of times I&#38;#39;d copy and pasted a &lt;code&gt;print STDERR &#38;quot;Here!&#38;quot;&lt;/code&gt; from one place to another and then scratched my head wondering which &lt;i&gt;Here&lt;/i&gt; was printing.&lt;/p&gt;

&lt;p&gt;Laziness is one of the virtues of a Perl programmer. Surely we can automate this? You bet we can.&lt;/p&gt;

&lt;p&gt;Acme::MetaSyntactic is a module that can create random memorable strings for us and the Acme-MetaSyntactic-Themes distribution on the CPAN contains a vast range of themes for it. For example, using the gems theme:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Acme::MetaSyntactic&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(gems)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;join&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39; &#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;metagems&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Produces output like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ruby amethyst girasol
    moonstone ivory sugilite
    jadeite tiger_s_eye jasper
    beryl lapis_lazuli diamond&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can easily use this technique to write a tiny little Perl script that outputs a print statement that contains unique-ish strings&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Acme::MetaSyntactic&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(batman)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;print STDERR &#38;quot;&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;literal&#34;&gt;q{ }&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;metabatman&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#38;quot;;\\n&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Executing this we can see our print statement with awesome 60s Batman type sound effects.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    print STDERR &#38;quot;wham_eth klonk\n&#38;quot;;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But how do we automate inserting this in our Perl code?&lt;/p&gt;

&lt;h3 id=&#34;Configuring-Your-Editor&#34;&gt;Configuring Your Editor&lt;/h3&gt;

&lt;p&gt;Modern editors are amazing things, Turing complete little bundles of wonder that can be configured to do almost anything, including executing a shell script and inserting the output of the script into your source code.&lt;/p&gt;

&lt;p&gt;I won&#38;#39;t tell you what editor to use (and you emacs and vim users probably know how to do this already) but I&#38;#39;ll let you in on the secret of how I do this with Sublime Text 3, my editor of choice.&lt;/p&gt;

&lt;p&gt;Sublime Text 3 has a complex plug-in system written in Python in which I&#38;#39;ve written many a tool. But, fear not, I need not concern myself with a non-Perl language in this Advent Calendar entry, for many existing plug-ins that can shell out exist that can be installed with Package Control without having to write a line of code. Using the &lt;a href=&#34;https://packagecontrol.io/packages/External%20Command&#34;&gt;External Command&lt;/a&gt; plug-in we can get our script to insert at the cursor every time we hit &lt;code&gt;alt-shift-b&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synSpecial&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;quot;&lt;span class=&#34;synStatement&#34;&gt;keys&lt;/span&gt;&#38;quot;: &lt;span class=&#34;synSpecial&#34;&gt;[&lt;/span&gt;&#38;quot;&lt;span class=&#34;synConstant&#34;&gt;alt+shift+b&lt;/span&gt;&#38;quot;&lt;span class=&#34;synSpecial&#34;&gt;]&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;quot;&lt;span class=&#34;synStatement&#34;&gt;caption&lt;/span&gt;&#38;quot;: &#38;quot;&lt;span class=&#34;synConstant&#34;&gt;print STDERR meta batman&lt;/span&gt;&#38;quot;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;quot;&lt;span class=&#34;synStatement&#34;&gt;command&lt;/span&gt;&#38;quot;: &#38;quot;&lt;span class=&#34;synConstant&#34;&gt;insert_command_output&lt;/span&gt;&#38;quot;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;quot;&lt;span class=&#34;synStatement&#34;&gt;args&lt;/span&gt;&#38;quot;: &lt;span class=&#34;synSpecial&#34;&gt;{&lt;/span&gt; &#38;quot;&lt;span class=&#34;synStatement&#34;&gt;cmdline&lt;/span&gt;&#38;quot;: &#38;quot;&lt;span class=&#34;synConstant&#34;&gt;/Users/mark/bin/printmetabatman&lt;/span&gt;&#38;quot; &lt;span class=&#34;synSpecial&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Configuring-Your-Terminal-Emulator&#34;&gt;Configuring Your Terminal Emulator&lt;/h3&gt;

&lt;p&gt;So, why isn&#38;#39;t running this in an editor sufficient? If you only ever edit code on your own box then everything is good...but what if you&#38;#39;re logged into a remote server via ssh that either doesn&#38;#39;t run your editor or choice or isn&#38;#39;t configured to have Acme::MetaSyntactic or your editor configuration?&lt;/p&gt;

&lt;p&gt;Rather than using the Terminal application bundled with OS X, these days I use an open source replacement called &lt;a href=&#34;https://www.iterm2.com/&#34;&gt;iTerm 2&lt;/a&gt;. As well as having cool features like being able to open files you &lt;code&gt;ls&lt;/code&gt; with a click, configurable highlighting of terminal output (to show where all the errors are when you tail a log), and allowing programs you run in it to pop up notifications outside the window, it also allows &lt;i&gt;co-processes&lt;/i&gt;. In iTerm parlance, co-processes are scripts that once launched get sent everything that the terminal is outputting. Anything they output is typed back into the terminal.&lt;/p&gt;

&lt;p&gt;In our case, we want to simply want to execute our same two line Perl script as a co-process so its output is typed at the terminal. That can be done from within the &lt;code&gt;Keys&lt;/code&gt; tab of the application&#38;#39;s preferences:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;iTerm2.png&#34; width=&#34;500&#34; height=&#34;294&#34;&gt;&lt;/center&gt;

&lt;h3 id=&#34;Making-an-OS-X-Service&#34;&gt;Making an OS X Service&lt;/h3&gt;

&lt;p&gt;What if we want to take it even further? Have a keyboard shortcut that doesn&#38;#39;t insert the text in a particular application but inserts the text &lt;i&gt;anywhere&lt;/i&gt; on OS X that OS X thinks it can take text input?&lt;/p&gt;

&lt;p&gt;OS X Services are global menu items that can be triggered by clicking on the title of the current running application next to the apple logo in the top left corner of the screen and selecting them from the &lt;code&gt;Services&lt;/code&gt; menu underneath. More importantly, they can also be assigned global keyboard shortcuts.&lt;/p&gt;

&lt;p&gt;The Automator application that is provided by Apple can be used to create Services that run Perl scripts: Launch Automator and select &#38;quot;Service&#38;quot; to create a new service. Search for the &lt;code&gt;Run Shell Script&lt;/code&gt; action then configure it to run the Perl script (you can write Perl code directly in this box and configure it to be executed with &lt;code&gt;/usr/bin/perl&lt;/code&gt;, but we&#38;#39;re re-using the same script as in the previous examples.) Finally set it so the Service takes &lt;code&gt;no input&lt;/code&gt; and tick the box so that &lt;code&gt;Output replaces selected text&lt;/code&gt;.&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;automator.png&#34; width=&#34;500&#34; height=&#34;294&#34;&gt;&lt;/center&gt;

&lt;p&gt;The service is installed as soon as you save it.&lt;/p&gt;

&lt;p&gt;Once you have created the service you can then assign a keyboard shortcut to it in System Preferences. Select the &lt;code&gt;Keyboard&lt;/code&gt; icon, click on the &lt;code&gt;Shortcuts&lt;/code&gt; tab and then pick &lt;code&gt;Services&lt;/code&gt; on the left. Scroll down till you find your service under &lt;code&gt;Text&lt;/code&gt; and click on the space to the right of the name to assign the shortcut.&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;prefs.png&#34; width=&#34;368&#34; height=&#34;322&#34;&gt;&lt;/center&gt;

&lt;h3 id=&#34;Keyboard-Maestro&#34;&gt;Keyboard Maestro&lt;/h3&gt;

&lt;p&gt;If you were paying close attention you&#38;#39;ll notice that previously I said that a service can be used &#38;quot;anywhere on OS X that &lt;i&gt;OS X thinks it can take text input&lt;/i&gt;&#38;quot;. What does that mean? It means that they can be used anywhere that the application is using the standard libraries to create a text input area. But not all applications use that (for example the previously mentioned iTerm2 and Sublime Text don&#38;#39;t use those, and the service cannot be used within them.)&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.keyboardmaestro.com/main/&#34;&gt;Keyboard Maestro&lt;/a&gt; is a commercial utility that can be used to control your Mac. One of the many things it can do is trigger a workflow whenever a key combination is pressed. That workflow can execute an external script and Keyboard Maestro can then simulate the keys on your keyboard being pressed. This means that the output from that script can be typed anywhere in any application running on your Mac, whether or not it&#38;#39;s explicitly expecting it.&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;km.png&#34; width=&#34;476&#34; height=&#34;277&#34;&gt;&lt;/center&gt;

&lt;h3 id=&#34;Typing-Autocompletion&#34;&gt;Typing Autocompletion&lt;/h3&gt;

&lt;p&gt;Another option to insert the text is to use a text expansion utility. For example, using the &lt;a href=&#34;https://smilesoftware.com/textexpander&#34;&gt;TextExpander&lt;/a&gt; program I can configure my computer so that every time I type &lt;code&gt;metaqq&lt;/code&gt; it deletes that text and quickly types the output of my Perl script:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;te.gif&#34; width=&#34;355&#34; height=&#34;130&#34;&gt;&lt;/center&gt;

&lt;p&gt;Setting this kind of script up with TextExpander is trivial; You just create a new macro and click on the &lt;code&gt;content&lt;/code&gt; header and select &lt;code&gt;Shell Script&lt;/code&gt; then enter the path to our existing script in the shebang line (or, you could write the Perl shell script here, directly in the text box.)&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;te.png&#34; width=&#34;360&#34; height=&#34;275&#34;&gt;&lt;/center&gt;

&lt;p&gt;Keyboard Maestro is a little more complex to use than Text Expander but can also be configured to do text expansion with a shell script. It can even be configured to match what typed text triggers the macro with regular expressions, which allows you to have a very crude way to type in variables. For example, to produce a macro where we can type &lt;code&gt;meta&#38;lt;theme&#38;gt;qq&lt;/code&gt; to select any of the installed Acme::MetaSyntactic themes:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;km.gif&#34;&gt;&lt;/center&gt;

&lt;p&gt;In order to work out what was typed in the script we need to set a variable to the &lt;code&gt;%TypedText%&lt;/code&gt; temporary variable, and then access it via an environment variable in our Perl script:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;km2.png&#34; width=&#34;494&#34; height=&#34;438&#34;&gt;&lt;/center&gt;

&lt;h3 id=&#34;The-True-Perl-Laziness&#34;&gt;The True Perl Laziness&lt;/h3&gt;

&lt;p&gt;So today we have truly embraced the Perl concept of laziness. Rather than have to spend five seconds typing in a print statement, we&#38;#39;ve developed a Perl script that generates suitable output for us and investigated at least six different ways to trigger it on a Mac. I&#38;#39;m sure you&#38;#39;ll all agree that that&#38;#39;s time well spent.&lt;/p&gt;

&lt;p&gt;swish bloop ker_sploosh thwape aiieee!&lt;/p&gt;

&lt;h3 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO:&lt;/h3&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Acme::MetaSyntatic&#34;&gt;Acme::MetaSyntatic&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.iterm2.com/&#34;&gt;iTerm 2&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.keyboardmaestro.com/main/&#34;&gt;Keyboard Maestro&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://smilesoftware.com/textexpander&#34;&gt;TextExpander&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-14T00:00:00Z</updated><category term="Perl"/><author><name>Mark Fowler</name></author></entry><entry><title>(JSON::)Paths in the snow</title><link href="http://perladvent.org/2015/2015-12-13.html"/><id>http://perladvent.org/2015/2015-12-13.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;One thing IT elves do a lot, is to munge data structures. In some departments, sources tell us, they use &lt;a href=&#34;https://metacpan.org/module/JSON::Path&#34;&gt;JSON::Path&lt;/a&gt; for it. It&#38;#39;s not an extensive tool, but it can come in handy.&lt;/p&gt;

&lt;p&gt;Despite its name, &lt;a href=&#34;https://metacpan.org/module/JSON::Path&#34;&gt;JSON::Path&lt;/a&gt; does not have much to do with JSON itself. It is rather an XPath-like query mini-language for querying structured data.&lt;/p&gt;

&lt;p&gt;For example, taking a data structure all elves are rather familiar with:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;children&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Xavier&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;nice&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;wants&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;label&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;T.S. Moe&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;      &lt;span class=&#34;word&#34;&gt;price&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;9.99&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;label&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;coloring book&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;price&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;5.45&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Alex&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;naughty&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;wants&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;label&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;rubber duck&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;price&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;6.57&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Elo&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;nice&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;wants&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;label&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;battle tiara&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;price&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;22.12&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;label&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;climbing gears&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;price&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;12.33&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We could extract the name of all naughty children via:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;JSON::Path&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw/ jpath /&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$JSON::Path::Safe&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@naughty&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;jpath&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$.children[?($_-&#38;gt;{status} eq &#38;quot;naughty&#38;quot; )].name&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which means &lt;code&gt;@naughty&lt;/code&gt; is now:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    [ &#38;quot;Alex&#38;quot; ]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or get the first gift request of all nice children:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@gifts&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;jpath&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$.children[?($_-&#38;gt;{status} eq &#38;quot;nice&#38;quot; )].wants[0]&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which means &lt;code&gt;@gifts&lt;/code&gt; is now:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    [ &#38;quot;T.S. Moe&#38;quot;, &#38;quot;battle tiara&#38;quot; ]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There is also the possibility to alter the structure directly via &lt;code&gt;jpath_map&lt;/code&gt;. For example, if we wanted to remove the naughty children and limit the wishlist of all nice children to their least expensive item (hey, it&#38;#39;s a tough economy for everybody), one could do:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;JSON::Path&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw/ jpath_map /&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# buh-bye naughty boys and naughty girls&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;jpath_map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;nice&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$.children&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# remove the status, as they are all nice, now&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;jpath_map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;delete&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;        &lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$.children[*]&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;#  let&#39;s be reasonable...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;List::MoreUtils&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw/ sort_by /&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;jpath_map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sort_by&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;price&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$.children[*].wants&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which means &lt;code&gt;$master_list&lt;/code&gt; finally contains:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    {
        children   [
            {
                name    &#38;quot;Xavier&#38;quot;,
                wants   {
                    label   &#38;quot;coloring book&#38;quot;,
                    price   5.45
                }
            },
            {
                name    &#38;quot;Elo&#38;quot;,
                wants   {
                    label   &#38;quot;climbing gears&#38;quot;,
                    price   12.33
                }
            }
        ]
    }&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/JSON::Path&#34;&gt;JSON::Path&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-13T00:00:00Z</updated><category term="Perl"/><author><name>yanick</name></author></entry><entry><title>Configuration Station</title><link href="http://perladvent.org/2015/2015-12-12.html"/><id>http://perladvent.org/2015/2015-12-12.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;The &lt;b&gt;best&lt;/b&gt; option for configuration.&lt;/p&gt;

&lt;p&gt;I wrote Config::Station after implementing a pattern I wrote about &lt;a href=&#34;https://blog.afoolishmanifesto.com/posts/configuration-station/&#34;&gt;a while ago&lt;/a&gt; another time or two.&lt;/p&gt;

&lt;p&gt;The overall gist of &lt;a href=&#34;https://metacpan.org/module/Config::Station&#34;&gt;Config::Station&lt;/a&gt; is that you define a simple configuration class that knows nothing about the file the config is loaded from:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MyApp::Config&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moo&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Types::Standard&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Int&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;port&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Int&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;root_dir&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;/var/myapp&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then you &lt;i&gt;inflate&lt;/i&gt; it with Config::Station:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$station&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Config::Station&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;config_class&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;MyApp::Config&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;env_key&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;MYAPP&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;location&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;.config.json&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$config&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$station&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So already we have a few nice details over most other config options out there:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;We know exactly what config values are supported&lt;/p&gt;

&lt;p&gt;I often get frustrated at trying to discover exactly what all config keys are used. Sometimes this isn&#38;#39;t even possible when it&#38;#39;s a mere hash.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We have defaults defined in a central location&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We have all of the validation that we&#38;#39;ve become used to&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Config::Station&lt;/code&gt;, like any good gift, gets progressively better as you learn more about it. Simply blessing a JSON file into an object is not the most impressive idea ever (though it is still pretty convenient, if I may say so myself.) One of the most important features of &lt;code&gt;Config::Station&lt;/code&gt; is that it overlays the loaded config with environment variables. So if you wanted to start two separate web servers running your application running on two servers it should be as easy as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; $ MYAPP_SERVER=Gazelle MYAPP_PORT=8080 myapp_server.pl &#38;amp;
 $ MYAPP_SERVER=Starman MYAPP_PORT=8081 myapp_server.pl &#38;amp;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&#38;#39;s really great, and really works well for my personal development flow, but it&#38;#39;s still just a taste of what you can do with it.&lt;/p&gt;

&lt;p&gt;See, the real beauty of &lt;code&gt;Config::Station&lt;/code&gt; is the delegation of the hard work to the configuration class. Here&#38;#39;s another example of cool things you can do, again using &lt;a href=&#34;https://metacpan.org/module/Moo&#34;&gt;Moo&lt;/a&gt; as the object system backing the configuration class:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MyApp::Config&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moo&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;JSONY&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;dsn&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;coerce&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;ref&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;JSONY&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;])&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We&#38;#39;re adding smarts here: If the value passed to us isn&#38;#39;t exactly in the format we want, we&#38;#39;re coercing it into the right format.&lt;/p&gt;

&lt;p&gt;You may not have heard of &lt;a href=&#34;https://metacpan.org/module/JSONY&#34;&gt;JSONY&lt;/a&gt;; it&#38;#39;s a weird thing but it&#38;#39;s great in cases like this. Here is how you could use it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; $ MYAPP_DSN=&#38;#39;dbi:ODBC:server=10.6.6.17 frew Password1!&#38;#39; myapp_server.pl&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, the attribute&#38;#39;s coercion uses &lt;code&gt;JSONY&lt;/code&gt; to parse our string into an arrayref with three values, suitable for passing to &lt;a href=&#34;https://metacpan.org/module/DBI&#34;&gt;DBI&lt;/a&gt; or &lt;a href=&#34;https://metacpan.org/module/DBIx::Class&#34;&gt;DBIx::Class&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Of course, nothing requires you to use &lt;code&gt;Moo&lt;/code&gt; or &lt;code&gt;Moose&lt;/code&gt;. The only requirement is that your class take a flat hashref as it&#38;#39;s sole argument. So if you wanted to do something really crazy you could go with raw OO:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MyApp::Config&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$class&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;bless&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;dsn&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;username&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;password&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$class&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;dsn&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;username&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;password&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Honestly I struggle to come up with an example that would warrant non-&lt;code&gt;Moo&lt;/code&gt; OO, but it is explicitly supported nonetheless. Maybe if you wanted to do some crazy OO like &lt;a href=&#34;https://metacpan.org/module/IO::All&#34;&gt;IO::All&lt;/a&gt; does where you do &lt;code&gt;bless Symbol::gensym(), $class&lt;/code&gt;?&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Config::Station&#34;&gt;Config::Station&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/JSONY&#34;&gt;JSONY&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-12T00:00:00Z</updated><category term="Perl"/><author><name>Arthur Axel &#34;fREW&#34; Schmidt</name></author></entry><entry><title type="html">Extracting more value out of your script&#38;#39;s comments</title><link href="http://perladvent.org/2015/2015-12-11.html"/><id>http://perladvent.org/2015/2015-12-11.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;&#38;#39;Twas the day before Christmas Eve and Blink the elf had just had a call telling him that he&#38;#39;d been reassigned to the NOC (North-Pole Operations Centre). &#38;quot;It&#38;#39;s an emergency, get over there pronto!&#38;quot;&lt;/p&gt;

&lt;p&gt;He quickly learned about the realities of the systems running Santa&#38;#39;s operation. Many of them created by different teams who rarely talked to each other, and who used whatever language and frameworks were hot at the time their project started. A mixture of command-line tools, SOAP-based web services, RESTful APIS, and so on.&lt;/p&gt;

&lt;p&gt;&#38;quot;It&#38;#39;s all glued together by Perl scripts that Jack wrote; when things go wrong he always knows how to get things running again. But Jack&#38;#39;s sick, so we need a Perl hacker to help us through tomorrow! Someone told me that you&#38;#39;re the elf who wrote the Prancer web framework, so I asked the Boss for you personally&#38;quot;.&lt;/p&gt;

&lt;p&gt;It turned out there was a collection of scripts, but the biggest complaint in the NOC was that no-one knew what they were doing as they were running (&#38;quot;when something goes wrong it&#38;#39;s always been Jack who works out what needs restarting, and at what step&#38;quot;). When Blink started looking at the scripts, his heart initially sank: they were enormous, and he only had a few hours before they had to be in use! But at least there were &lt;i&gt;some&lt;/i&gt; comments, describing what was going on:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# get list of children&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;pile&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# look them up in the Good Register&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;pile&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# get scanned images of letters to the Boss&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;even&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;more&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;code&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Blink remembered &lt;a href=&#34;https://metacpan.org/module/Smart::Comments&#34;&gt;Smart::Comments&lt;/a&gt;, one of Damian Conway&#38;#39;s modules, and realised it might help him out. Blink added &lt;code&gt;use Smart::Comments&lt;/code&gt; and modified the highest level comments:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Smart::Comments&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;### get list of children&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;code&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;### looking children up in the Good Register&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Any comments that started with three or more hash characters (&lt;code&gt;&#38;quot;#&#38;quot;&lt;/code&gt;) were printed out as the script ran.&lt;/p&gt;

&lt;p&gt;The NOC elves thought this was great, but there were some parts of the scripts that took quite a while to run, so the next thing for Blink to do was to give a bit more detail. There were a lot of places where code looped over countries, so first he wanted to print out the country being processed:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$country&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@countries&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    #### Processing country: $country&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Any perl expession can be put after the colon, so Blink was quickly able to display a country name, which Santa was assigned, as so on. On this next level of comments Blink used four hashes. When using &lt;code&gt;Smart::Comments&lt;/code&gt; he could specify what level of comments should be handled:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Smart::Comments&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;###&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;####&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This let the NOC decide how verbose the various scripts were when running. Blink then added the &lt;code&gt;-ENV&lt;/code&gt; option:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Smart::Comments&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-ENV&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;###&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;####&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This let the NOC specify the what level of diagnostics they wanted, just by setting the &lt;code&gt;Smart_Comments&lt;/code&gt; environment variable:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    export Smart_Comments=&#38;#39;###:####&#38;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The NOC can also set this environment variable to &lt;code&gt;0&lt;/code&gt; to turn off the diagnostics completely.&lt;/p&gt;

&lt;p&gt;There were still a lot of places where the scripts would iterate over large numbers of things, like children. Here it wasn&#38;#39;t feasible to display each child&#38;#39;s name, but they wanted some indication of progress. Blink used &lt;code&gt;Smart::Comments&lt;/code&gt;&#38;#39;s progress meters for these situations:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$child&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@children&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;   &lt;span class=&#34;comment&#34;&gt;### OCR [===|     ] % done&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;ocr_letter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$child&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This displays a progress bar and a completion percentage. It will also track how long each step takes and estimate the time remaining, telling the NOC when a loop was close to finishing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    OCR [=================|  ] 91% done  (about 20 seconds remaining)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After adding these three types of smart comments to all of the scripts, the NOC elves were very happy. Together they were able to get through Christmas Eve with no major mishaps.&lt;/p&gt;

&lt;p&gt;The chief NOC elf asked Blink if he&#38;#39;d like to join the NOC full time, to work on a new microservices architecture. &#38;quot;Don&#38;#39;t do it&#38;quot;, whispered one of the junior NOC elves; &#38;quot;he says something like that &lt;i&gt;every&lt;/i&gt; year. Why do you think Jack pulled a sickie?&#38;quot;&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Smart::Comments&#34;&gt;Smart::Comments&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-11T00:00:00Z</updated><category term="Perl"/><author><name>Neil Bowers</name></author></entry><entry><title>Just What Are You Installing Now?</title><link href="http://perladvent.org/2015/2015-12-10.html"/><id>http://perladvent.org/2015/2015-12-10.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Have you ever been installing a Perl module and wondered why the heck a module was being installed? How the heck is &lt;i&gt;that&lt;/i&gt; module a dependency of &lt;i&gt;this&lt;/i&gt; module? So have I. So I decided to work it out, and when it all got too much to understand easily, I decided to make some pretty graphs:&lt;/p&gt;

&lt;h3 id=&#34;cpanfile&#34;&gt;cpanfile&lt;/h3&gt;

&lt;p&gt;The quest to understand why my distribution is requiring all these other modules to be installed starts with my &lt;code&gt;cpanfile&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;cpanfile&lt;/code&gt; format is natural language way of specifying the dependencies that your module needs. Here&#38;#39;s an example one from Stepford:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Carp&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;File::Temp&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Forest::Tree&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;List::AllUtils&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Log::Dispatch&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Log::Dispatch::Null&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Module::Pluggable::Object&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Moose&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Moose::Role&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MooseX::Params::Validate&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MooseX::StrictConstructor&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MooseX::Types&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MooseX::Types::Combine&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MooseX::Types::Common::Numeric&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MooseX::Types::Common::String&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MooseX::Types::Moose&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;MooseX::Types::Path::Class&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Parallel::ForkManager&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Path::Class&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Scalar::Util&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Scope::Guard&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Throwable::Error&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Time::HiRes&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;1.9726&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Try::Tiny&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;namespace::autoclean&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;parent&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;perl&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;5.010&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;strict&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;warnings&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;test&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;ExtUtils::MakeMaker&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;File::Copy&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;File::Spec&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;IPC::Signal&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Log::Dispatch::Array&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Differences&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Fatal&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::More&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0.96&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Requires&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Warnings&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;autodie&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;lib&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;perl&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;5.010&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;test&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;recommends&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;CPAN::Meta&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;2.120900&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;configure&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;ExtUtils::MakeMaker&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;perl&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;5.006&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;develop&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Code::TidyAll&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0.24&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;File::Spec&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;IO::Handle&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;IPC::Open3&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;IPC::Signal&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Perl::Critic&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;1.123&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Perl::Tidy&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;20140711&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Pod::Coverage::TrustPod&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::CPAN::Changes&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0.19&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Code::TidyAll&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0.24&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::EOL&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::More&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0.88&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::NoTabs&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Pod&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;1.41&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Pod::Coverage&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;1.08&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Spelling&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0.12&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Synopsis&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;0&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Test::Version&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;1&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see this is essentially a list of modules, along with their minimum version requirements, that this distribution either requires or recommends. You&#38;#39;ll also note that are multiple sections for the dependencies, allowing you to specify what dependencies you need to run this module on a production server and which modules you just need when you&#38;#39;re testing or developing the code.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;cpanfile&lt;/code&gt; file, which is typically distributed in the top level directory of a distribution, can either be created manually or automatically through inspection of your code by tools like the Dist::Zilla::Plugin::CPANFile plugin for Dist::Zilla. As well as being directly consumed by various tools, it&#38;#39;s often used to produce things like the &lt;code&gt;Makefile.PL&lt;/code&gt; and &lt;code&gt;META.yaml&lt;/code&gt; and &lt;code&gt;META.json&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;In our case we want to parse it so we can start to build our dependency tree.&lt;/p&gt;

&lt;h3 id=&#34;Parsing-the-cpanfile-format&#34;&gt;Parsing the cpanfile format&lt;/h3&gt;

&lt;p&gt;The cpanfile format can easily be parsed with the Module::CPANfile module to give us the list of direct dependencies we need:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@module_names&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sort&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Module::CPANfile&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;cpanfile&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prereqs&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;merged_requirements&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;([&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;runtime&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;build&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;test&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;configure&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;develop&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;requires&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;])&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;required_modules&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whoa! That was a little dense. Let&#38;#39;s break this down a little by adding more variables and comments:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# parse the on disk cpanfile&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cpanfile&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Module::CPANfile&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;cpanfile&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# get the CPAN::Meta::Prereqs instance that represents the prerequisites&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$prereqs&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cpanfile&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prereqs&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# get the CPAN::Meta::Requirements that represents the requirements.  We want&lt;br /&gt;# all the possible requirements that this module requires (i.e. those needed&lt;br /&gt;# on a live server, but also those needed to build and test and develop it&lt;br /&gt;# too) but not optional recommendations&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$requirements&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$prereqs&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;merged_requirements&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;([&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;runtime&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;build&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;test&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;configure&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;develop&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;requires&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;]);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# And turn that into a sorted list of modules names&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@module_names&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sort&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$requirements&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;required_modules&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We now know the immediate direct dependencies of our distribution in terms of module names, but how can we work out what distributions those modules are contained in, and in turn what those distributions themselves depend on?&lt;/p&gt;

&lt;h3 id=&#34;Using-MetaCPAN-to-Produce-a-Full-Dependency-Tree&#34;&gt;Using MetaCPAN to Produce a Full Dependency Tree&lt;/h3&gt;

&lt;p&gt;MetaCPAN is, aside from being the most useful place to view the documentation and browse the code of everything on the CPAN, at its heart an Elasticsearch database that contains meta information on each of the modules. We can use the MetaCPAN API to ask for the dependencies of modules, their dependencies, and so on to create a graph of each of the modules.&lt;/p&gt;

&lt;p&gt;Let&#38;#39;s look at the code that&#38;#39;s needed to do this. First we create an instance of the &lt;code&gt;MetaCPAN::Client&lt;/code&gt; that can be used to connect to the MetaCPAN API that sits on top of the Elasticsearch database.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mcpan&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MetaCPAN::Client&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;ua&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;HTTP::Tiny::Mech&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;mechua&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;WWW::Mechanize::Cached&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;cache&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;CHI&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;driver&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;File&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;root_dir&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;/tmp/metacpan-cache&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This invocation makes use of an on-disk cache for each request to MetaCPAN so when we run this script multiple times we don&#38;#39;t need to re-lookup information we&#38;#39;ve already fetched. This both speeds things up and makes the MetaCPAN admins considerably less grumpy!&lt;/p&gt;

&lt;p&gt;The code to look up the distribution a module comes in is straightforward:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;module_to_dist&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($module_name)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;unless&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mod_obj&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mcpan&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$module_name&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$dist&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mod_obj&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;distribution&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;warn&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;memoize&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;module_to_dist&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will allow us to pass in module names like &lt;code&gt;HTTP::Response&lt;/code&gt; and get back responses like &lt;code&gt;HTTP-Message&lt;/code&gt; to tell us the distribution that contains &lt;code&gt;HTTP::Response&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Similarly we can get the release object back for a given distribution:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;dist_to_release&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($dist_name)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$release&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;unless&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$release&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mcpan&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;release&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dist_name&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;warn&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$release&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;memoize&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;dist_to_release&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This release object has a &lt;code&gt;dependency&lt;/code&gt; method that returns an array reference containing the names of all the modules this particular release (in this case the latest one on the CPAN for that name) depends on.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dep&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$release&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;dependency&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@*&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot; * $dep &#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Using these two methods we can then easily build a hash mapping dependencies:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;add_mapping&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($from, $to)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$from&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;||=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[];&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$from&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@*&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$to&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;lookup_module&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($module_name)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;mod:$module_name&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$module_name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;perl&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Module::CoreList&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;first_release&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$module_name&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # work out the distribution for this module&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dist&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;module_to_dist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$module_name&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;add_mapping&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;mod:$module_name&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;dist:$dist&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lookup_dist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$dist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;lookup_dist&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($dist)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;dist:$dist&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$release&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;dist_to_release&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dist&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # okay, need to work out this distribution&#39;s dependencies and repeat&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dep&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$release&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;dependency&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@*&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mod&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dep&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mod&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;perl&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Module::CoreList&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;first_release&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mod&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;add_mapping&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;dist:$dist&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;mod:$mod&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lookup_module&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mod&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@module_names&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;add_mapping&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;cpanfile&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;mod:$_&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lookup_module&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then you can obviously dump that out to as JSON into a
&lt;a href=&#34;stepford.js&#34;&gt;JavaScript file&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;data=&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;encode_json&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;%map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Graphing&#34;&gt;Graphing&lt;/h3&gt;

&lt;p&gt;As comprehensive as this data structure is, it&#38;#39;s not easy to understand at a glance. What we want to do is turn this into some sort of easy to follow directed graph with nodes for the distributions and modules connected together with lines representing the dependencies.&lt;/p&gt;

&lt;p&gt;Any number of JavaScript libraries can be used to turn the chunk of JavaScript we just created into an on-screen graph in a web browser. My personal favorite is VivaGraph, simply because CPAN dependency graphs can get very very large and it has excellent performance on larger graphs, especially when used in WebGL mode opposed to the default SVG rendering engine.&lt;/p&gt;

&lt;p&gt;The actual code to build the graph is fairly straightforward:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;graph&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Viva&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;Graph&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;graph&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;nodesAlreadyAdded&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;maybeAddNode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;nodeName&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;nodesAlreadyAdded&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;nodeName&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;])&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;nodesAlreadyAdded&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;nodeName&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;graph&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;addNode&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;nodeName&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;addEdge&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;maybeAddNode&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;maybeAddNode&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;graph&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;addLink&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;addEdge&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;VivaGraph is quite customizable, and the full code to fiddle with the
presentation options, switch on WebGL mode, add custom colors, labels, alter
the length of the links depending what&#39;s linking, etc, etc is all worth 
&lt;a href=&#34;graph-script.js&#34;&gt;taking a look&lt;/a&gt;.

&lt;h3 id=&#34;Conclusion&#34;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Several projects I work on install half of the CPAN. While this is a good thing (since I don&#38;#39;t have to write or maintain all the code that constitutes half of the CPAN,) I often find I end up depending on some hard to install or unreliable module. By graphing my dependency tree I can work out exactly why I&#38;#39;m depending on a module and work out what steps I can take to mitigate the situation.&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Module::CPANfile&#34;&gt;Module::CPANfile&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/MetaCPAN::Client&#34;&gt;MetaCPAN::Client&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/WWW::Mechanize::Cached&#34;&gt;WWW::Mechanize::Cached&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/anvaka/VivaGraphJS&#34;&gt;https://github.com/anvaka/VivaGraphJS&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-10T00:00:00Z</updated><category term="Perl"/><author><name>Mark Fowler</name></author></entry><entry><title>Scrape the Halls</title><link href="http://perladvent.org/2015/2015-12-09.html"/><id>http://perladvent.org/2015/2015-12-09.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Here&#38;#39;s a shocker: the Santa Factories doesn&#38;#39;t manufacture all of the children&#38;#39;s toys for Christmas. For particular toys and special requests, the elves will buy the toys, and just take care of the wrapping and delivery. But don&#38;#39;t you think they are going around with this outsourcing in an indiscriminate manner; the Big Man in Red made it very clear that toys should not be bought from big mega-corporations, but only from Mom&#38;#39;n&#38;#39;Pop shops, where they are built out of love and honest desire to make children happy.&lt;/p&gt;

&lt;p&gt;Noble sentiments. But one that throws some wrenches in the finely-tuned North Pole&#38;#39;s toy managing software. Mega-corporations might be soulless, but they usually have systems backed by solid REST APIs. Mom and Pop shops? A basic website is usually all you get. It&#38;#39;s not pretty, but for those cases dev&lt;i&gt;elf&lt;/i&gt;opers have to revert to crude but effective web scraping.&lt;/p&gt;

&lt;p&gt;One of their tools is &lt;a href=&#34;https://metacpan.org/module/Web::Query&#34;&gt;Web::Query&lt;/a&gt;, which is heavily inspired by the ubiquitous jQuery. With it, they can use CSS selectors, or even XPath expressions, to access and munge their target websites.&lt;/p&gt;

&lt;h3 id=&#34;A-Working-Example&#34;&gt;A Working Example&lt;/h3&gt;

&lt;p&gt;Let&#38;#39;s look at the wonderful Vermont Teddy Bear website. Santa approves of this company because they always make sure that they ship their teddy bears in packaging with air holes (so the bears can breathe) and each bear gets free complimentary health care (where by the company will fix the bear if it&#38;#39;s sick and shipped back to the Teddy Bear Hospital.)&lt;/p&gt;

&lt;p&gt;Here&#38;#39;s &lt;a href=&#34;http://www.vermontteddybear.com/Category/Hobbies.aspx?View=All&#34;&gt;the current page&lt;/a&gt; for all their hobby bears:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;vtb.jpg&#34; width=&#34;709&#34; height=&#34;649&#34;&gt;&lt;/center&gt;

&lt;p&gt;If our elves are going to work out the price of the products they need to take a look at the source code of the page with their browser&#38;#39;s Web Inspector. It turns out the part of the page&#38;#39;s HTML markup they&#38;#39;re going to be interested in looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;products&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ProductImageDashed&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;...&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ProductImageDescr&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ctl00_MainContent_UcC2CategorySellGroups1_dlSellGroups_ctl00_lnkSellGroupText&#38;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;               &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;../SellGroup/15-yoga-bear.aspx&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ctl00_MainContent_UcC2CategorySellGroups1_dlSellGroups_ctl00_LabelProductName&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;span class=&#34;synUnderlined&#34;&gt;15&#38;quot; Yoga Bear&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;br&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ctl00_MainContent_UcC2CategorySellGroups1_dlSellGroups_ctl00_LabelPricing&#38;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;               &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;productsprice&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;../SellGroup/15-yoga-bear.aspx&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;span class=&#34;synUnderlined&#34;&gt;$79.99&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ProductImageDashed&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;...&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ProductImageDescr&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ctl00_MainContent_UcC2CategorySellGroups1_dlSellGroups_ctl01_lnkSellGroupText&#38;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;               &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;../SellGroup/Ballerina-Bear.aspx&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ctl00_MainContent_UcC2CategorySellGroups1_dlSellGroups_ctl01_LabelProductName&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;span class=&#34;synUnderlined&#34;&gt;15&#38;quot; Ballerina Bear&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;br&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;ctl00_MainContent_UcC2CategorySellGroups1_dlSellGroups_ctl01_LabelPricing&#38;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;               &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;productsprice&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;../SellGroup/Ballerina-Bear.aspx&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;span class=&#34;synUnderlined&#34;&gt;$69.99&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;...&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;A-Small-Script&#34;&gt;A Small Script&lt;/h3&gt;

&lt;p&gt;Using &lt;a href=&#34;https://metacpan.org/module/Web::Query&#34;&gt;Web::Query&lt;/a&gt;, the elves are able to retrieve all the information on that page rather easily with a tiny tiny script:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;5.20.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;experimental&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;postderef&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Data::Printer&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Web::Query&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%toys&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;wq&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;http://www.vermontteddybear.com/Category/Hobbies.aspx?View=All&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;#products li .ProductImageDescr&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;a:first-child&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$price&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;.productsprice&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$price&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@*&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%toys&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&#38;#39;s break this down a little to see what those elves are up to:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;wq&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;http://www.vermontteddybear.com/Category/Hobbies.aspx?View=All&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This goes to the web and downloads a page, and creates a Web::Query object containing the top node of that page.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;#products li .ProductImageDescr&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This returns a new Web::Query object (based on the old Web::Query object) that contains all the nodes that match the CSS selector we passed in (and nothing else.) In this case it&#38;#39;s all the ProductImageDescr divs in &lt;code&gt;&#38;lt;li&#38;gt;&lt;/code&gt; elements inside the element with the &lt;code&gt;products&lt;/code&gt; id assigned to it.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This calls the passed subroutine multiple times, once per previously matched node, with a new Web::Query object that contains just the one node that we&#38;#39;re currently processing passed via the context variable &lt;code&gt;$_&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;a:first-child&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$price&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;.productsprice&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This finally does further lookups &lt;i&gt;from the point of view each node the map receives&lt;/i&gt;. So, for example, the &lt;code&gt;.productsprice&lt;/code&gt; selector just matches the price under this particular &lt;code&gt;.ProductImageDescr&lt;/code&gt; node, not every &lt;code&gt;.productsprice&lt;/code&gt; in the entire document.&lt;/p&gt;

&lt;h3 id=&#34;Filtering&#34;&gt;Filtering&lt;/h3&gt;

&lt;p&gt;After all that, running that script kinda produces some of the right data:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    # perl get_bears.pl
    {
        &#38;#39;15&#38;quot; Artist Bear&#38;#39;                       &#38;quot;$69.99&#38;quot;,
        &#38;#39;15&#38;quot; Aviator Bear &#38;#39;                     &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;quot; Ballerina Bear&#38;#39;                    &#38;quot;$69.99&#38;quot;,
        &#38;#39;15&#38;quot; Basketball Bear&#38;#39;                   &#38;quot;$69.99&#38;quot;,
        &#38;#39;15&#38;quot; Cooking Bear&#38;#39;                      &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;quot; Everything Grows with Love Bear&#38;#39;   &#38;quot;$69.99&#38;quot;,
        &#38;#39;15&#38;quot; Golfer Bear&#38;#39;                       &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;#39;&#38;#39; Gone Fishin&#38;#39; Bear&#38;#39;                &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;quot; Handy Bear&#38;#39;                        &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;quot; Lady Golfer&#38;#39;                       &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;quot; Martial Arts Bear&#38;#39;                 &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;#39;&#38;#39; Racecar Driver Bear&#38;#39;              &#38;quot;$69.99&#38;quot;,
        &#38;#39;15&#38;quot; Runner Bear&#38;#39;                       &#38;quot;$69.99&#38;quot;,
        &#38;#39;15&#38;quot; Sewing Bear&#38;#39;                       &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;quot; Skier Bear&#38;#39;                        &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;quot; Soccer Bear&#38;#39;                       &#38;quot;$69.99&#38;quot;,
        &#38;#39;15&#38;quot; Surf&#38;#39;s Up Bear&#38;#39;                    &#38;quot;$69.99&#38;quot;,
        &#38;#39;15&#38;quot; Tennis Bear&#38;#39;                       &#38;quot;$79.99&#38;quot;,
        &#38;#39;15&#38;quot; Train Engineer&#38;#39;                    &#38;quot;$69.99&#38;quot;,
        &#38;#39;15&#38;quot; Yoga Bear&#38;#39;                         &#38;quot;$79.99&#38;quot;,
        &#38;#39;Arts &#38;amp; Crafts Bears&#38;#39;                   &#38;quot;&#38;quot;,
        &#38;#39;Bears for Dance Lovers&#38;#39;                &#38;quot;&#38;quot;,
        &#38;#39;Bears For Peace&#38;#39;                       &#38;quot;&#38;quot;,
        Music                                   &#38;quot;&#38;quot;,
        &#38;#39;Religious Bears&#38;#39;                       &#38;quot;&#38;quot;
    }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However, Santa don&#38;#39;t really want the data for the categories at the bottom of the page that doesn&#38;#39;t include pricing. Using the &lt;code&gt;filter&lt;/code&gt; method we&#38;#39;re able to discard any result which the passed subroutine doesn&#38;#39;t return true for:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;5.20.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;experimental&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;postderef&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Data::Printer&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Web::Query&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%toys&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;wq&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;http://www.vermontteddybear.com/Category/Hobbies.aspx?View=All&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;#products li .ProductImageDescr&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;length&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;.productsprice&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;a:first-child&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$price&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;.productsprice&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$price&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@*&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%toys&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Success!&lt;/p&gt;

&lt;h3 id=&#34;Setting-the-User-Agent&#34;&gt;Setting the User Agent&lt;/h3&gt;

&lt;p&gt;A few days later the elves were in a bit of a pickle. Their script had stopped working! It turned out that the Vermont Teddy Bear company had been having some problems with people who weren&#38;#39;t on the nice list, and they&#38;#39;d blocked the standard Perl user agent string, and the elves&#38;#39; code was collateral damage.&lt;/p&gt;

&lt;p&gt;Because elves are conscientious, they decided to change the UserAgent to make sure that the shops can see that it&#38;#39;s their web scrapers that visited their sites with a minor code change at the top of all their Web::Scraper scripts:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$web::Query::UserAgent&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;LWP::UserAgent&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;agent&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;SnowReindeer/4.0.0.0&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# pronounced &#38;quot;four-HO-HO-HO!&#38;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Web::Query&#34;&gt;Web::Query&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Mojo::UserAgent&#34;&gt;Mojo::UserAgent&lt;/a&gt; and &lt;a href=&#34;https://metacpan.org/module/Mojo::DOM&#34;&gt;Mojo::DOM&lt;/a&gt; can also do similar things&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://www.vermontteddybear.com/&#34;&gt;Vermont Teddy Bear&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-09T00:00:00Z</updated><category term="Perl"/><author><name>A Team Effort</name></author></entry><entry><title>Live programming perl with Reply</title><link href="http://perladvent.org/2015/2015-12-08.html"/><id>http://perladvent.org/2015/2015-12-08.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Of all the things Perl is and is not, it is most definitely a dynamic language. We don&#38;#39;t run Perl through a compiler and then run the resulting executable, we just give perl some code and it runs it. In a language like C or Java, we&#38;#39;d have to rebuild every time we wanted to run a test, but Perl allows me to hit &#38;#39;save&#38;#39; in my editor, alt-tab to my terminal and hit &lt;code&gt;&#38;lt;up&#38;gt;&#38;lt;enter&#38;gt;&lt;/code&gt; to rerun my test.&lt;/p&gt;

&lt;p&gt;Obviously this helps speed up my test workflow enormously, but we can still do better. What if we could edit our application while it was running? This is the promise of a REPL (Read Eval Print Loop). In this article we&#38;#39;ll be exploring a new REPL for Perl called &lt;code&gt;Reply&lt;/code&gt; to do some live-coding.&lt;/p&gt;

&lt;p&gt;You&#38;#39;ll need a recent-ish perl installed as well as git if you&#38;#39;re going to follow along&lt;/p&gt;

&lt;h3 id=&#34;Installation&#34;&gt;Installation&lt;/h3&gt;

&lt;p&gt;Let&#38;#39;s try installing Reply through cpanminus with the &lt;code&gt;cpanm&lt;/code&gt; utility (my prompt is the simple &lt;code&gt;%&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    % cpanm Reply Term::ReadLine::Gnu Proc::InvokeEditor
    --&#38;gt; Working on Reply
    Fetching http://www.cpan.org/authors/id/D/DO/DOY/Reply-0.37.tar.gz ... OK
    Configuring Reply-0.37 ... OK
    ==&#38;gt; Found dependencies: Config::INI::Reader::Ordered
    --&#38;gt; Working on Config::INI::Reader::Ordered
    Fetching http://www.cpan.org/authors/id/R/RJ/RJBS/Config-INI-Reader-Ordered-0.020.tar.gz ... OK
    Configuring Config-INI-Reader-Ordered-0.020 ... OK
    Building and testing Config-INI-Reader-Ordered-0.020 ... OK
    Successfully installed Config-INI-Reader-Ordered-0.020
    Building and testing Reply-0.37 ... OK
    Successfully installed Reply-0.37
    2 distributions installed&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Don&#38;#39;t worry if your output looks different, so long as the modules installed successfully, you&#38;#39;re good to go! We&#38;#39;re also installing a bunch of other modules that are required for some of the plugins we&#38;#39;ll try later to work.&lt;/p&gt;

&lt;h3 id=&#34;Getting-Started&#34;&gt;Getting Started&lt;/h3&gt;

&lt;p&gt;Let&#38;#39;s open a repl with the &lt;code&gt;reply&lt;/code&gt; command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    % reply
    /Users/user/.replyrc not found. Generating a default...
    0&#38;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Okay, looks good so far. Let&#38;#39;s try running some basic Perl:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    0&#38;gt;  $i = &#38;quot;foo&#38;quot;
    Global symbol &#38;quot;$i&#38;quot; requires explicit package name at reply input line 1.
    BEGIN not safe after errors--compilation aborted at reply input line 7.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Okay, so we&#38;#39;re running under &lt;i&gt;strict&lt;/i&gt;. Excellent! I also notice that readline bindings work, so you can use the arrow keys and standard readline shortcuts easily to edit your input. Autocomplete &#38;#39;just works&#38;#39;(tm) as well (it&#38;#39;s on the &lt;code&gt;TAB&lt;/code&gt; key)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    1&#38;gt; my $i = &#38;quot;foo&#38;quot;
    $res[0] = &#38;#39;foo&#38;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Okay, the basics work. Note also that we don&#38;#39;t need to put a semicolon at the end of a line. When you hit enter, it will treat it as a complete statement. That&#38;#39;s an important limitation that&#38;#39;s worth mentioning.&lt;/p&gt;

&lt;p&gt;Let&#38;#39;s see if we can load it into an existing project. Quit reply with &lt;code&gt;Ctrl-c&lt;/code&gt; and find some code.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    % cd ~/code/asset-pack # my local copy of https://github.com/jjl/asset-pack.git
    % reply -Ilib # -Ilib = add &#38;#39;lib&#38;#39; to @INC so we can see those perl modules
    0&#38;gt; use Asset::Pack;
    1&#38;gt; &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Hurray, that worked. Sadly Asset::Pack isn&#38;#39;t useful unless you want to package an asset as a Perl file, so let&#38;#39;s use the repl to explore &lt;code&gt;List::Util&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    1&#38;gt; use List::Util qw(first);
    2&#38;gt; first {/abc/} &#38;quot;def&#38;quot;, &#38;quot;hij&#38;quot;
    $res[0] = undef
    3&#38;gt; first {/abc/} &#38;quot;abc&#38;quot;, &#38;quot;def&#38;quot;
    $res[1] = &#38;#39;abc&#38;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These two simple examples show off &#38;#39;first&#38;#39;, which takes a block. Let&#38;#39;s look at its prototype:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    4&#38;gt; prototype(\&#38;amp;first)
    $res[2] = &#38;#39;&#38;amp;@&#38;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Plugins-Intro&#34;&gt;Plugins Intro&lt;/h3&gt;

&lt;p&gt;At this point you can already do a fair amount. Now let&#38;#39;s look at that &lt;code&gt;.replyrc&lt;/code&gt; file that reply said it wrote earlier:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    # less ~/.replyrc
    script_line1 = use strict
    script_line2 = use warnings
    script_line3 = use 5.020001
    
    [Interrupt]
    [FancyPrompt]
    [DataDumper]
    [Colors]
    [ReadLine]
    [Hints]
    [Packages]
    [LexicalPersistence]
    [ResultCache]
    [Autocomplete::Packages]
    [Autocomplete::Lexicals]
    [Autocomplete::Functions]
    [Autocomplete::Globals]
    [Autocomplete::Methods]
    [Autocomplete::Commands]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wow, that&#38;#39;s quite a lot. Comparing against &lt;a href=&#34;https://metacpan.org/release/Reply&#34;&gt;https://metacpan.org/release/Reply&lt;/a&gt;, I see that&#38;#39;s most of the plugins that ship in the core distribution!&lt;/p&gt;

&lt;p&gt;Here&#38;#39;s what these plugins do (and what you&#38;#39;re getting out of the box!)&lt;/p&gt;

&lt;table class=&#34;pretty-table&#34;&gt;

&lt;thead&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;Purpose&lt;/td&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr class=&#34;alt&#34;&gt;
&lt;td&gt;Interrupt&lt;/td&gt;
&lt;td&gt;Stop long-running code with &lt;code&gt;ctrl-c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;FancyPrompt&lt;/td&gt;
&lt;td&gt;Adds a line counter to the prompt&lt;/td&gt;
&lt;/tr&gt;

&lt;tr class=&#34;alt&#34;&gt;
&lt;td&gt;DataDumper&lt;/td&gt;
&lt;td&gt;Formats results with &lt;code&gt;Data::Dumper&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Colors&lt;/td&gt;
&lt;td&gt;Colors results&lt;/td&gt;
&lt;/tr&gt;

&lt;tr class=&#34;alt&#34;&gt;
&lt;td&gt;ReadLine&lt;/td&gt;
&lt;td&gt;Enables ReadLine input method (keybindings)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Hints&lt;/td&gt;
&lt;td&gt;Enables &lt;code&gt;strict&lt;/code&gt; to work, among others (persists hints)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr class=&#34;alt&#34;&gt;
&lt;td&gt;Packages&lt;/td&gt;
&lt;td&gt;Makes &lt;code&gt;package&lt;/code&gt; declarations work&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;LexicalPersistence&lt;/td&gt;
&lt;td&gt;Makes &lt;code&gt;my&lt;/code&gt; declarations work&lt;/td&gt;
&lt;/tr&gt;

&lt;tr class=&#34;alt&#34;&gt;
&lt;td&gt;ResultCache&lt;/td&gt;
&lt;td&gt;Results are put into &lt;code&gt;@res&lt;/code&gt; for later use&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Autocomplete::*&lt;/td&gt;
&lt;td&gt;Autocompletion of various types&lt;/td&gt;
&lt;/tr&gt;

&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;If you don&#38;#39;t want some of those, simply delete those lines from your config file and they won&#38;#39;t be loaded next time you start a repl.&lt;/p&gt;

&lt;p&gt;Take a look at &lt;a href=&#34;https://metacpan.org/release/Reply&#34;&gt;https://metacpan.org/release/Reply&lt;/a&gt; to see all the basic plugins.&lt;/p&gt;

&lt;h3 id=&#34;Editing-multiple-lines&#34;&gt;Editing multiple lines&lt;/h3&gt;

&lt;p&gt;One of the handier plugins is &lt;a href=&#34;https://metacpan.org/module/Reply::Plugin::Editor&#34;&gt;Reply::Plugin::Editor&lt;/a&gt;, which allows you to edit multiple lines in your text editor of choice. Add this to the bottom of your &lt;code&gt;.replyrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    [Editor]
    editor=emacs # or vim, nano etc...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now when you&#38;#39;re in reply and you type &lt;code&gt;#e&lt;/code&gt;, your editor will open. When you save the file and quit your editor, the code will be evaluated all at once. This allows you to define subroutines more easily because now you can split statements over multiple lines.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    0&#38;gt; #e
    &#38;lt;editor opens&#38;gt;
    sub hello {
      &#38;quot;Hello, @{[shift]}.&#38;quot;;
    }
    &#38;lt;save and close&#38;gt;
    1&#38;gt; hello(&#38;quot;world&#38;quot;)
    $res[0]=&#38;quot;Hello, world.&#38;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h3&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Reply&#34;&gt;Reply&lt;/a&gt; - Reply documentation&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Reply::Plugin::AutoRefresh&#34;&gt;Reply::Plugin::AutoRefresh&lt;/a&gt; - Automatic code reloading when files change&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Reply::Plugin::CollapseStack&#34;&gt;Reply::Plugin::CollapseStack&lt;/a&gt; - Truncate stack traces by default&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Reply::Plugin::CarpReply&#34;&gt;Reply::Plugin::CarpReply&lt;/a&gt; - Get a repl on uncaught exception&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Reply::Plugin&#34;&gt;Reply::Plugin&lt;/a&gt; - Base class for Reply plugins (develop your own!)&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-08T00:00:00Z</updated><category term="Perl"/><author><name>James Laver</name></author></entry><entry><title>Sharing templates will get you on the nice list</title><link href="http://perladvent.org/2015/2015-12-07.html"/><id>http://perladvent.org/2015/2015-12-07.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;It was the night before Christmas Eve and the elves in Santa&#38;#39;s Grotto were typing away on their keyboards getting ready for the tomorrow night, making sure the last minute issues were fixed. Unfortunately the day had started badly - the elves in the QA department had reported three bugs in quick succession with their website. If the elves didn&#38;#39;t address the problems in the next few hours, Christmas would be ruined!&lt;/p&gt;

&lt;h3 id=&#34;The-Problems&#34;&gt;The Problems&lt;/h3&gt;

&lt;p&gt;The QA elves had identified three problems with the website the team packing the sleigh use to record their work:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;If I filter with the widget the text is in suddenly in English, but if I hit reload it&#39;s Elvish as it should be!&lt;/li&gt;
  &lt;li&gt;If I browse to the page it looks great, but if I refresh it goes bad!&lt;/li&gt;
  &lt;li&gt;The total at the bottom of this table is wrong! Aren&#39;t there tests?&lt;/li&gt;
 &lt;/ol&gt;

&lt;h4 id=&#34;Pronto-the-Front-End-Develfoper&#34;&gt;Pronto the Front End Dev&lt;i&gt;elf&lt;/i&gt;oper&lt;/h4&gt;

&lt;p&gt;The leader of elvish front-end development team scratched her head for a moment. The first two seemed to be similar bugs, but in one case the &#38;quot;client side&#38;quot; was wrong and in the other the &#38;quot;server side&#38;quot; was wrong.&lt;/p&gt;

&lt;p&gt;After six cups of elf eggnog, the answer finally hit her! The JavaScript code that ran on the client side had its own templating language, and so the changes to the templates had to be made to both templates that generated the output. The templates that generate the page on the server side and the JavaScript templates that create HTML from the JSON loaded from the server in &lt;a href=&#34;https://en.wikipedia.org/wiki/AJAJ&#34;&gt;AJAJ&lt;/a&gt; requests need to be identical! Any differences would end up with the bugs they were seeing.&lt;/p&gt;

&lt;p&gt;After much cross referencing between the two templating languages (and worrying about the minutiae of the different syntaxes) Pronto managed to commit a fix just a few hours before the deadline.&lt;/p&gt;

&lt;p&gt;Sighing, Proto thought &lt;i&gt;having to maintain two templating languages and two sets of identical templates is always going to be a huge pain for my team&lt;/i&gt;&lt;/p&gt;

&lt;h4 id=&#34;Retro-the-Back-End-Develfoper&#34;&gt;Retro the Back-End Dev&lt;i&gt;elf&lt;/i&gt;oper&lt;/h4&gt;

&lt;p&gt;Meanwhile the lead of back-end team looked for the source of the third and final bug, the table total bug. Her team grepped as hard as they could around &lt;code&gt;lib/SantasWorkshop/&lt;/code&gt; but the table logic was nowhere to be found!&lt;/p&gt;

&lt;p&gt;Finally, one of the team had a realisation - the logic wasn&#38;#39;t in the modules, it was in one of the back-end templates themselves! And he was right, the addition - and the bug - was in the template file. Retro shook her head; no wonder there wasn&#38;#39;t a test for it! Quickly she fixed the bug and pushed out a new release, but no-one in her team felt right about not being able to add a regression test for the code.&lt;/p&gt;

&lt;p&gt;Sighing, Retro thought &lt;i&gt;having all this logic in the templates where it can&#38;#39;t be tested is always going to be a huge pain for my team&lt;/i&gt;&lt;/p&gt;

&lt;h3 id=&#34;Santas-Mustache&#34;&gt;Santa&#38;#39;s Mustache&lt;/h3&gt;

&lt;p&gt;When Santa finally got back from his around the world dash, he scheduled debriefing meetings with his developers to learn about what could be improved for next year. When he heard all about the last minute problems that had nearly ended in worldwide disappointment for the children his forehead wrinkled under his big red hat. He sat quietly for a moment, stroking his mustache...&lt;/p&gt;

&lt;p&gt;A smile crept across Santa&#38;#39;s face. &#38;quot;Ho ho ho, I know of a solution to both your problems&#38;quot;, he said, his grin widening. &#38;quot;Have you heard of &lt;b&gt;Mustache&lt;/b&gt;?&#38;quot; The elves shook their head, but one of them brought up the website on his icePhone 6.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://mustache.github.io/&#34;&gt;Mustache&lt;/a&gt; provides logic-less templates and has parsers for multiple languages including JavaScript and Perl!&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;By being logic-less you&#38;#39;re forced to put your logic into your Perl modules&lt;/p&gt;

&lt;p&gt;where it&#38;#39;s easy to write unit tests for your subroutines.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By being usable in JavaScript and Perl you can write one set of templates and&lt;/p&gt;

&lt;p&gt;render them on the server side or the client side as needed.&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;Hogan.js-and-Text::Hogan&#34;&gt;Hogan.js and Text::Hogan&lt;/h3&gt;

&lt;p&gt;There are actually a few options even within Perl and JavaScript for mustache libraries. The elves gave a few a try, and eventually settled on &lt;a href=&#34;https://github.com/twitter/hogan.js&#34;&gt;hogan.js&lt;/a&gt; (from Twitter) and its Perl-ish clone &lt;a href=&#34;https://metacpan.org/pod/Text::Hogan&#34;&gt;Text::Hogan&lt;/a&gt; (from your story-teller.)&lt;/p&gt;

&lt;p&gt;In Perl:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Text::Hogan::Compiler&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Hello, {{name}}!&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$template&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Text::Hogan::Compiler&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;compile&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$template&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Santa&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In JavaScript:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synIdentifier&#34;&gt;var&lt;/span&gt; text = &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;Hello, {{name}}!&#38;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;var&lt;/span&gt; template = Hogan.compile(text);&lt;br /&gt;&lt;br /&gt;console.log(template.render(&lt;span class=&#34;synIdentifier&#34;&gt;{&lt;/span&gt;name: &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;Santa&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;}&lt;/span&gt;);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Despite the &#38;quot;logic-less&#38;quot; claim Mustache templates do provide some simple constructs you can use for optional blocks or looping blocks.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Text::Hogan::Compiler&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Time::Moment&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;&#39;END_MUSTACHE&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;heredoc_content&#34;&gt;&#38;lt;h1&#38;gt;Santa&#39;s Dashboard&#38;lt;/h1&#38;gt;&lt;br /&gt;&lt;br /&gt;&#38;lt;h2&#38;gt;Nice/Naughty List&#38;lt;/h2&#38;gt;&lt;br /&gt;&#38;lt;ul&#38;gt;&lt;br /&gt;{{#list}}&lt;br /&gt;&#38;lt;li&#38;gt;{{name}} - {{nice}}&#38;lt;/li&#38;gt;&lt;br /&gt;{{/list}}&lt;br /&gt;&lt;br /&gt;&#38;lt;h2&#38;gt;Is it Christmas yet?&#38;lt;/h2&#38;gt;&lt;br /&gt;{{#is_it_christmas_yet}}&#38;lt;p&#38;gt;Yes, it&#39;s Christmas!&#38;lt;/p&#38;gt;{{/is_it_christmas_yet}}&lt;br /&gt;{{^is_it_christmas_yet}}&#38;lt;p&#38;gt;No, it&#39;s not Christmas yet.&#38;lt;/p&#38;gt;{{/is_it_christmas_yet}}&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;END_MUSTACHE&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%data&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;sort&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$b&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;nice&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;nice&#38;quot;&lt;/span&gt;    &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(Fred Betty)&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;nice&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;naughty&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(Barney Wilma)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is_it_christmas_yet&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Time::Moment&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;strftime&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;%m-%d&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;12-25&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$template&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Text::Hogan::Compiler&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;compile&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$template&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;%data&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see &lt;code&gt;#&lt;/code&gt; is used for ifs and loops, and &lt;code&gt;^&lt;/code&gt; is used for negative checks. For more details see the &lt;a href=&#34;http://mustache.github.io/mustache.5.html&#34;&gt;mustache(5)&lt;/a&gt; man page.&lt;/p&gt;

&lt;h3 id=&#34;One-more-issue&#34;&gt;One more issue&lt;/h3&gt;

&lt;p&gt;The elves had gleefully replaced all their old templates with new mustache based ones, and written tests for all their code that was previously locked away in template files. Hooray! But then one day, shortly before next Christmas, another bug report came in:&lt;/p&gt;

&lt;p&gt;&#38;quot;I don&#38;#39;t think we can use these new templates during the Christmas rush. Our metrics show that the site has gotten much slower since we switched.&#38;quot;&lt;/p&gt;

&lt;p&gt;Luckily one of the elvish development team was ready for this. Not wanting to fall into the trap of premature optimization he hadn&#38;#39;t yet used one of hogan.js and Text::Hogan&#38;#39;s most powerful features: pre-rendering.&lt;/p&gt;

&lt;p&gt;Using Text::Hogan::Compiler&#38;#39;s &lt;code&gt;compile&lt;/code&gt; method (like in the examples above) means you only compile a template to Perl code once per process (due to clever internal caching.) Using pre-rendering however, you can actually get at the generated Perl code and cache it somewhere on disk / in memcache, etc.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Text::Hogan::Compiler&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Hello, {{name}}!&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$perl_code&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Text::Hogan::Compiler&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;compile&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;as_string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$perl_code&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The Perl code that comes out the other end isn&#38;#39;t pretty, but it renders really quickly:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;code&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$p&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;Hello, &#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;name&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$p&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)));&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;!&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;fl&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;partials&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;subs&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The JavaScript library hogan.js can pull the same trick with its &#38;quot;hulk&#38;quot; command-line tool or with various grunt, gulp or webpack plugins.&lt;/p&gt;

&lt;p&gt;Once the change to pre-compile the templates went live the site was even faster than it was on the old templates. Christmas was saved again!&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO:&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Text::Hogan&#34;&gt;Text::Hogan&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Text::Hogan::Compiler&#34;&gt;Text::Hogan::Compiler&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://mustache.github.io/mustache.5.html&#34;&gt;http://mustache.github.io/mustache.5.html&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-07T00:00:00Z</updated><category term="Perl"/><author><name>Alex Balhatchet</name></author></entry><entry><title>Calculating cooking times the easy way</title><link href="http://perladvent.org/2015/2015-12-06.html"/><id>http://perladvent.org/2015/2015-12-06.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;We&#38;#39;ve all been there when cooking - you have one thing that should be cooked at 200&#38;#x2103; for 30 minutes, another that asks for 220&#38;#x2103; for 35 minutes, and something else that only wants 180&#38;#x2103; for 26 minutes. However, you only have the one oven, so there&#38;#39;s going to have to be compromises!&lt;/p&gt;

&lt;p&gt;After one too many times guessing appropriate adjustments in my head, I decided &#38;quot;this sounds like something a computer can be doing for me quickly&#38;quot;. So, enter &lt;a href=&#34;https://metacpan.org/module/Convert::CookingTimes&#34;&gt;Convert::CookingTimes&lt;/a&gt;. Given a set of item names, temperatures and durations, it works out the average of the temperatures requested, then adjusts the cooking times to suit (so things being cooked at a higher temperature than normal will get their cooking times reduced and vice-versa). It will then present a list of instructions telling you what temperature to pre-heat the oven to, and what should be put in and when, for everything to end up done at the same time.&lt;/p&gt;

&lt;p&gt;So, let&#38;#39;s say we&#38;#39;re doing a nice tasty English Christmas dinner. We have:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;A bunch of potatoes that need roasting for 45 minutes at 200&#38;#x2103;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A turkey that&#38;#39;s meant to be cooked for two hours at 180&#38;#x2103;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And the stuffing that needs to go in for quartre of an hour at 210&#38;#x2103;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a chart this looks something like this:&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;before-meal.png&#34; width=&#34;567&#34; height=&#34;380&#34;&gt;&lt;/center&gt;

&lt;p&gt;However, since we need to cook them all at the same temperature we need to adjust the cooking times to compensate. Let&#38;#39;s use our Perl module:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$temperature&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$steps&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Convert::CookingTimes&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;adjust_times&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Roast spuds&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;temp&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;45&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Turkey&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;      &lt;span class=&#34;word&#34;&gt;temp&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;180&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;120&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Stuffing&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;temp&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;210&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Dumper&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;temperature&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$temperature&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;steps&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$steps&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The steps are returned from &lt;code&gt;adjust_times&lt;/code&gt; as a reference to an array of hashrefs. These are the same items as passed in, reordered to be in the order you need to put them in the oven. Each of them is a hashref with the keys &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;adjusted_time&lt;/code&gt; (how long to cook that thing for in total) and, for convenience, &lt;code&gt;time_until_next&lt;/code&gt; (the amount of time to wait before the next item in the list is added to the oven in order for everything to be done at the same time). When we run our little script we get this handy output:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$VAR1&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;steps&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;name&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Turkey&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;adjusted_time&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;108&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;time_until_next&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;63&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;time_until_next&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;29&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;adjusted_time&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;45&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;name&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Roast spuds&#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;name&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Stuffing&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;adjusted_time&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;16&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;temperature&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;200&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Plotting these on a chart shows us how the time and temperature for the potatoes and stuffings have been adjusted from the original values (marked with the blue circles):&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;after-meal.png&#34; width=&#34;567&#34; height=&#34;380&#34;&gt;&lt;/center&gt;

&lt;p&gt;To make our lives even easier, the output of &lt;code&gt;adjust_times&lt;/code&gt; can be passed to &lt;code&gt;summarise_instructions&lt;/code&gt; to produce a set of human-readable summarised instructions like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Convert::CookingTimes&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;summarise_instructions&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;Convert::CookingTimes&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;adjust_times&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Roast spuds&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;temp&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;45&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Turkey&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;      &lt;span class=&#34;word&#34;&gt;temp&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;180&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;120&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Stuffing&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;temp&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;210&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which produces the highly readable output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  Warm oven up to 200 degrees.
  Cooking the whole meal will take 108 minutes.
  Add Turkey and cook for 63 minutes
  Add Roast spuds and cook for 29 minutes
  Add Stuffing and cook for 16 minutes&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course, it&#38;#39;s an algorithm, not a cook, so you&#38;#39;ll want to use a bit of common sense especially if the range of temperatures was particularly wide - maybe use a meat thermometer to check for a safe internal temperature if you&#38;#39;re unsure!&lt;/p&gt;

&lt;p&gt;For ultimate laziness, I have a little web interface on my home server which presents various stats and CRUD interfaces etc - including one to store the cooking times and temperatures for things I cook commonly, along with a page I can go and tick the things I&#38;#39;m planning to cook, hit submit, and the stored times and temperatures are passed to Convert::CookingTimes to produce a list of steps to follow easily. Now, if I can just automate the actual cooking away too... hmm, I wonder if that food delivery website Just Eat has an API...&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Convert::CookingTimes&#34;&gt;Convert::CookingTimes&lt;/a&gt;&lt;/p&gt;

&lt;/div&gt;</summary><updated>2015-12-06T00:00:00Z</updated><category term="Perl"/><author><name>David Precious</name></author></entry><entry><title>Improving User Messages</title><link href="http://perladvent.org/2015/2015-12-05.html"/><id>http://perladvent.org/2015/2015-12-05.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Better-Messages-Please&#34;&gt;Better Messages Please&lt;/h2&gt;

&lt;p&gt;The new product owner was determined to make an impression on the site as quickly as possible, so she produced a list of &#38;quot;quick wins&#38;quot; for us to work on. Number one on her list was the quality of our error messages.&lt;/p&gt;

&lt;p&gt;Like pretty much every piece of software, our error messages suck. When users enter data, we validate it and tell them if there were any problems. We display messages like &#38;quot;1 error(s) were found&#38;quot;. It&#38;#39;s down to programmer laziness of course. And the wrong kind of laziness at that. But it seemed to be a simple enough thing to fix.&lt;/p&gt;

&lt;p&gt;I moved the ticket into &#38;quot;in progress&#38;quot; and reached for Lingua::EN::Inflect, only to find something interesting: Lingua::EN::Inflect is now in maintenance mode and has been superceeded by a new module called Lingua::EN::Inflexion. The notice in Lingua::EN::Inflect says that the new module &#38;quot;offers a cleaner and more convenient interface, has many more features (including plural-&#38;gt;singular inflexions), and is also much better tested&#38;quot;. It&#38;#39;s written by Damian Conway, so those claims seem likely to be accurate. I settled down to read the documentation.&lt;/p&gt;

&lt;h2 id=&#34;Singulars-and-Plurals&#34;&gt;Singulars and Plurals&lt;/h2&gt;

&lt;p&gt;The problem with the message is that it doesn&#38;#39;t know whether it needs to use singular or plural versions of the words in the text. Lingua::EN::Inflexion makes it easy to start with a singular noun and get the plural version.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@singulars&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw[cow pig sheep]&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@singulars&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$_ -&#38;gt; &#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;noun&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;plural&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which gives us:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    cow -&#38;gt; cows
    pig -&#38;gt; pigs
    sheep -&#38;gt; sheep&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can also go in the other direction.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@plurals&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw[cows pigs sheep]&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@plurals&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$_ -&#38;gt; &#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;noun&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;singular&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This outputs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    cows -&#38;gt; cow
    pigs -&#38;gt; pig
    sheep -&#38;gt; sheep&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also ask the object whether its invocant was singular or plural.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@nouns&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw[cow pigs sheep]&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@nouns&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$_ is singular&#38;quot;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;noun&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;is_singular&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$_ is plural&#38;quot;&lt;/span&gt;   &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;noun&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;is_plural&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will tell us:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    cow is singular
    pigs is plural
    sheep is singular
    sheep is plural&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that, unsurprisingly, &#38;quot;sheep&#38;quot; is both singular and plural.&lt;/p&gt;

&lt;p&gt;You can also use the &lt;code&gt;as_regex()&lt;/code&gt; to get a regex that matches both the singular and plural versions of the noun.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Ermintrude is the best of all the cows&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;noun&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;cow&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;as_regex&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$&#38;amp;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;$&#38;amp; will contain &#38;quot;cows&#38;quot;, not &#38;quot;cow&#38;quot;. And it&#38;#39;s even cleverer than that.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Ermintrude is ye best of all ye kine&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;noun&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;cow&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;as_regex&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$&#38;amp;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Because &#38;quot;kine&#38;quot; is an obscure old plural for &#38;quot;cow&#38;quot;.&lt;/p&gt;

&lt;p&gt;If you print the value returned from &lt;code&gt;noun(&#38;#39;cow&#38;#39;)-&#38;gt;as_regex&lt;/code&gt;, you&#38;#39;ll see that it is &lt;code&gt;(?^i:kine|cows|cow)&lt;/code&gt; - so it&#38;#39;s case insensitive too.&lt;/p&gt;

&lt;h2 id=&#34;Verbs-and-Adjectives&#34;&gt;Verbs and Adjectives&lt;/h2&gt;

&lt;p&gt;Lingua::EN::Inflexion doesn&#38;#39;t just work on nouns. You can inflect verbs and adjectives too using the &lt;code&gt;verb()&lt;/code&gt; and &lt;code&gt;adj()&lt;/code&gt; constructors.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@verbs&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw[is has sits]&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@verbs&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;The plural of $_ is &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;verb&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;plural&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which produces:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    The plural of is is are
    The plural of has is have
    The plural of sits is sit&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@adjectives&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw[my your his]&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@adjectives&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;The plural of $_ is &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;adj&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;plural&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which gives:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    The plural of my is our
    The plural of your is your
    The plural of his is their&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For more complex requirements, you can get the present participle, past tense and past participle of verbs.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@verbs&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw[is has sits]&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@verbs&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;The present participle of $_ is &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;verb&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;pres_part&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;The past tense of $_ is &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;verb&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;past&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;The past participle of $_ is &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;verb&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;past_part&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which produces:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;present&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;participle&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;being&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;past&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tense&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;was&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;past&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;participle&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;been&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;present&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;participle&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;having&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;past&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tense&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;had&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;past&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;participle&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;had&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;present&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;participle&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sits&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sitting&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;past&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tense&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sits&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sat&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;past&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;participle&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sits&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sat&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;Building-a-Message&#34;&gt;Building a Message&lt;/h2&gt;

&lt;p&gt;So now we have all of the pieces that we need to construct our message. We need to know how many errors were found. Let&#38;#39;s assume that&#38;#39;s in &lt;code&gt;$count&lt;/code&gt;. Then our code looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$count &#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$count&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;noun&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;error&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;singular&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;noun&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;error&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;plural&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;&lt;br /&gt;}&lt;br /&gt;$msg =. &#39;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;;&lt;br /&gt;if ($count == 1) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;$msg .= verb(&#39;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;was&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;)-&#38;gt;singular;&lt;br /&gt;} else {&lt;br /&gt;&#38;nbsp;&#38;nbsp;$msg .= verb(&#39;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;was&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;)-&#38;gt;plural&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39; found&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now you can start to see why so many systems make do with the terrible messages that we are trying to get rid of here. It&#38;#39;s just too complicated to write code like this every time you want to display a message to the user.&lt;/p&gt;

&lt;p&gt;You can try to make it a little simpler, I suppose.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cardinality&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$count&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;singular&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;plural&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$msg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$count &#38;quot;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;noun&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;error&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$cardinality&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39; &#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;verb&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;was&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$cardinality&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39; was found&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But it&#38;#39;s really not that much better. There has to be a better way. And, of course, that&#38;#39;s really why I&#38;#39;m writing this article.&lt;/p&gt;

&lt;h2 id=&#34;Inflecting-Sentences&#34;&gt;Inflecting Sentences&lt;/h2&gt;

&lt;p&gt;Lingua::EN::Inflexion exports four routines. We&#38;#39;ve seen three of them (&lt;code&gt;noun()&lt;/code&gt;, &lt;code&gt;verb()&lt;/code&gt;, and &lt;code&gt;adj()&lt;/code&gt;). The fourth one is called &lt;code&gt;inflect()&lt;/code&gt; and that&#38;#39;s the one which solves our problem and gives us our &#38;quot;quick win&#38;quot;.&lt;/p&gt;

&lt;p&gt;The subroutine takes a single string argument, where the string contains some special markup defining how you want the string processed. This string is expanded into a new string which is then returned.&lt;/p&gt;

&lt;p&gt;In the simplest case, you would use it like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;inflect&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;&#38;lt;#:$_&#38;gt; &#38;lt;N:error&#38;gt; &#38;lt;V:was&#38;gt; found&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    0 errors were found
    1 error was found
    2 errors were found
    3 errors were found&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Simply by changing the number that is interpolated into the string, the noun and verb have both been changed appropriately.&lt;/p&gt;

&lt;p&gt;We have used three of &lt;code&gt;inflect()&lt;/code&gt;&#38;#39;s special mark-up tags here. &lt;code&gt;&#38;lt;#:...&#38;gt;&lt;/code&gt; sets and displays the number which will be used in the rest of the output and &lt;code&gt;&#38;lt;N:...&#38;gt;&lt;/code&gt; and &lt;code&gt;&#38;lt;V:...&#38;gt;&lt;/code&gt; can be used to insert nouns and verbs which will be inflected. There&#38;#39;s a fourth tag, &lt;code&gt;&#38;lt;A:...&#38;gt;&lt;/code&gt; which can be used for adjectives, as you can see in this (slightly contrived) example.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;inflect&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;The report had &#38;lt;#:$_&#38;gt; &#38;lt;N:authors&#38;gt; &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;&#38;lt;A:our&#38;gt; recommendations are ... &#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which produces the following output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    The report had 1 author my recommendations are ... 
    The report had 2 authors our recommendations are ... 
    The report had 3 authors our recommendations are ...&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;Improving-the-Output&#34;&gt;Improving the Output&lt;/h2&gt;

&lt;p&gt;This is already much better than the output than you get from many programs, but there are easy ways to make it better. We can start by displaying &#38;quot;No&#38;quot; rather than &#38;quot;0&#38;quot;. This is achieved by adding an &lt;code&gt;n&lt;/code&gt; option to the &lt;code&gt;&#38;lt;#:...&#38;gt;&lt;/code&gt; tags. Options are added between the command character (the &lt;code&gt;#&lt;/code&gt;, &lt;code&gt;N&lt;/code&gt;, &lt;code&gt;V&lt;/code&gt; or &lt;code&gt;A&lt;/code&gt;) and the colon.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;inflect&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;&#38;lt;#n:$_&#38;gt; &#38;lt;N:error&#38;gt; &#38;lt;V:was&#38;gt; found&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives us:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    no errors were found
    1 error was found
    2 errors were found
    3 errors were found&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Some people prefer that zero items are displayed as singular rather than plural. We can accommodate that by using &lt;code&gt;s&lt;/code&gt; instead of &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;inflect&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;&#38;lt;#s:$_&#38;gt; &#38;lt;N:error&#38;gt; &#38;lt;V:was&#38;gt; found&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output then changes to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    no error was found
    1 error was found
    2 errors were found
    3 errors were found&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you would rather have &#38;quot;a&#38;quot; or &#38;quot;an&#38;quot; when the count is one, then you can use &lt;code&gt;a&lt;/code&gt; (and you can stack options, so you can use it in addition to either &lt;code&gt;n&lt;/code&gt; or &lt;code&gt;s&lt;/code&gt;).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;inflect&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;&#38;lt;#na:$_&#38;gt; &#38;lt;N:error&#38;gt; &#38;lt;V:was&#38;gt; found&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which gives us:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    no errors were found
    an error was found
    2 errors were found
    3 errors were found&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&#38;#39;s quite common to spell out the numbers when the count is small. If you use the &lt;code&gt;w&lt;/code&gt; option, then &lt;code&gt;inflect()&lt;/code&gt; will do that for numbers up to 10.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;inflect&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;&#38;lt;#naw:$_&#38;gt; &#38;lt;N:error&#38;gt; &#38;lt;V:was&#38;gt; found&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    no errors were found
    an error was found
    two errors were found
    nine errors were found
    ten errors were found
    11 errors were found&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, you can use &lt;code&gt;f&lt;/code&gt; to get fuzzy descriptions of the numbers.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Lingua::EN::Inflexion&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;inflect&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;&#38;lt;#f:$_&#38;gt; &#38;lt;N:error&#38;gt; &#38;lt;V:was&#38;gt; found&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which gives us:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    no errors were found
    one error was found
    a couple of errors were found
    a few errors were found
    several errors were found
    many errors were found&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;Finally---A-Real-Quick-Win&#34;&gt;Finally - A Real Quick Win&lt;/h2&gt;

&lt;p&gt;Users have become used to the &#38;quot;1 error(s) was found&#38;quot; style of message because it is ubiquitous. And that&#38;#39;s because fixing the problem isn&#38;#39;t exactly hard, it&#38;#39;s just tedious. There&#38;#39;s too much code to write to fix one small niggle in the user experience. Mostly, we think it&#38;#39;s not worth the effort.&lt;/p&gt;

&lt;p&gt;But the &lt;code&gt;inflect()&lt;/code&gt; subroutine fixes that. Now getting it right is as trivial as it should be. That&#38;#39;s the right kind of laziness. Damian was obviously getting bored of writing all of that code every time he wanted a grammatically satisfying user message, so he decided to fix the problem by writing a solution that he (and, through the wonder of CPAN, everyone else) could use to easily produce vastly improved messages.&lt;/p&gt;

&lt;p&gt;So our product manager got her quick win. And now yours can too.&lt;/p&gt;

&lt;p&gt;And your users will get a much better user experience.&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Lingua::EN::Inflexion&#34;&gt;Lingua::EN::Inflexion&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-05T00:00:00Z</updated><category term="Perl"/><author><name>Dave Cross</name></author></entry><entry><title type="html">Help! Rudolf&#38;#39;s Nose Won&#38;#39;t Light Up!</title><link href="http://perladvent.org/2015/2015-12-04.html"/><id>http://perladvent.org/2015/2015-12-04.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Often we find ourselves writing code that copes with &lt;i&gt;optional&lt;/i&gt; dependencies; Code that will use a module to do amazing things if it&#38;#39;s installed, but will muddle through with some lesser code path if that dependency is missing or unavailable on the system. When developing this code we need to test how the code works in both situations, preferably without breaking parts of our system setup just to check that the alternative code paths still work!&lt;/p&gt;

&lt;p&gt;How can we do this? Gather round, I have a story to tell...&lt;/p&gt;

&lt;h3 id=&#34;A-Christmas-Tale&#34;&gt;A Christmas Tale&lt;/h3&gt;

&lt;p&gt;At the north pole Cyber-Santa was in a bit of a pickle because he&#38;#39;d forgotten to charge the batteries for his new Robo-Reindeer&#38;#39;s light-up nose! How would he be able to find his way through the dark and deliver techno-toys to all the good programmers and sysadmins?&lt;/p&gt;

&lt;p&gt;Cyber-Santa was stressing out and whining on Twitter when one of his older elves reminded him that cost over-runs on the Reindeer Upgrade Project meant that he was still using the old sleigh, and that still had mounting brackets for old oil lamps.&lt;/p&gt;

&lt;p&gt;&#38;quot;But do we know that those lamps still work? Are they bright enough?&#38;quot;, Cyber-Santa asked&lt;/p&gt;

&lt;p&gt;&#38;quot;Oh yes&#38;quot;, replied the elf. &#38;quot;Don&#38;#39;t you remember, last Christmas we weren&#38;#39;t sure whether all the new Robo-Reindeer would be ready in time, so we did our &lt;a href=&#34;https://en.wikipedia.org/wiki/Sinterklaas&#34;&gt;test run&lt;/a&gt; both with and without cybernetic cervids, and everything worked just fine.&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;Let me show you how we tested this&#38;quot;, said the elf elaborated, &#38;quot;I&#38;#39;ll take you step by step through what we normally do. First, we dig the sleigh out from under that snowdrift. Would you mind doing it, only my poor old back is giving me gyp right now....and then could you fetch the reindeer and attach them to the sleigh?&#38;quot;,&lt;/p&gt;

&lt;p&gt;So Santa dug out the sleigh, fetched the reindeer, got kicked by the reindeer, harnessed them and &lt;i&gt;finally&lt;/i&gt; climbed up into the driver&#38;#39;s seat, all sweaty and bruised and smelling of reindeer.&lt;/p&gt;

&lt;p&gt;&#38;quot;So at this point, we&#38;#39;re ready to go, right?&#38;quot; asked the elf.&lt;/p&gt;

&lt;p&gt;&#38;quot;Yes!&#38;quot;, said Cyber-Santa.&lt;/p&gt;

&lt;p&gt;&#38;quot;Wrong!&#38;quot;, replied the elf, &#38;quot;We&#38;#39;re not yet ready. If you turn to page two of your Sleigh Operations Manual you&#38;#39;ll see the pre-flight checklist. The ninety fourth item on the list (after &#38;#39;are the presents tied down?&#38;#39; and &#38;#39;do you have &lt;a href=&#34;https://en.wikipedia.org/wiki/A_Twisted_Christmas&#34;&gt;banging choonz&lt;/a&gt; queued up on your iPod?&#38;#39;) is &#38;#39;is the robot providing sufficient lighting to navigate by?&#38;#39;&#38;quot;.&lt;/p&gt;

&lt;p&gt;And so Santa checked, and the glowing Robo-NoZe&#38;trade; wasn&#38;#39;t working because of that flat battery.&lt;/p&gt;

&lt;p&gt;&#38;quot;And after checklist item ninety four it tells you that if it isn&#38;#39;t working you should use an oil lamp, doesn&#38;#39;t it&#38;quot;, scolded the elf.&lt;/p&gt;

&lt;p&gt;Santa looked a bit sheepish and apologised, muttering something about being too eager to get his deliveries done so he could relax with a pint and some pork scratchings.&lt;/p&gt;

&lt;p&gt;&#38;quot;I&#38;#39;ll let you off this time&#38;quot;, scolded the elf, &#38;quot;but don&#38;#39;t do it again.&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;But ... but ...&#38;quot; Santa said hesitantly &#38;quot;how do we know it will work?&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;Oh, right, I was going to show you how we tested this wasn&#38;#39;t I. Sorry, I&#38;#39;m getting forgetful in my old age. Let&#38;#39;s go indoors and simulate it on your laptop where it&#38;#39;ll be nice and warm&#38;quot; smirked the elf, who really preferred the previous Santa, because the elf&#38;#39;s children got to play with left over toys and far preferred traditional wooden blocks and balls and things instead of the modern nonsense that Cyber-Santa was obsessed with.&lt;/p&gt;

&lt;h3 id=&#34;Modeling-With-Perl&#34;&gt;Modeling With Perl&lt;/h3&gt;

&lt;p&gt;&#38;quot;First let&#38;#39;s simulate what you just did&#38;quot;, said the elf. &#38;quot;We&#38;#39;ll create a sleigh object, and a factory class to simulate the field that the reindeer come from.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sleigh&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sleigh&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@reindeer&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ReindeerFactory&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;fetch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&#38;quot;Then we&#38;#39;ll harness the reindeer to the sleigh and have the sleigh run through the pre-flight checks because you&#38;#39;re so forgetful. Then, once the pre-flight checks are complete we can get going:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$sleigh&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;harness&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@reindeer&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$sleigh&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;pre_flight&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # FIXME, deliver presents here&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&#38;quot;So far, so simple. Now, consider that right now your pasture contains Robo-Reindeer, but previously it contained normal reindeer. So the ReindeerFactory has to look something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ReindeerFactory&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$reindeer_class&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;use RoboReindeer&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;RoboReindeer&#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;use BioReindeer&#38;quot;&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;BioReindeer&#38;quot;&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;No reindeer found\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;fetch&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$number_wanted&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$reindeer_class&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$number_wanted&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&#38;quot;I see&#38;quot;, said Santa, &#38;quot;so if the RoboReindeer module is installed (or if in real life I&#38;#39;ve got RoboReindeer in the pasture) then the factory will give me those, otherwise it&#38;#39;ll give me BioReindeer. Very clever. That looks like a pain to test though.&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;Yes, unfortunately it is&#38;quot; admitted the elf. &#38;quot;We had to run through the whole damned process twice, once for Robo-Reindeer, once for normal ones, being very careful to keep the two completely separate.&#38;quot;&lt;/p&gt;

&lt;p&gt;Santa was very thankful that he had elves to do that sort of hard work for him, but thought that it looked like a jolly useful technique for some of his hobby projects. &#38;quot;If only I could automate that in Perl...&#38;quot; mused Santa. But he put that aside, because he had a busy two days ahead of him.&lt;/p&gt;

&lt;h3 id=&#34;Magic-in-INC&#34;&gt;Magic in @INC&lt;/h3&gt;

&lt;p&gt;After he&#38;#39;d done his two days work for the whole year, and was stretched out on the sofa with a glass of brandy and some mince pies, Santa was still wondering how to automate that. Obviously he could wrap all his tests in a shell script that would install/uninstall modules as appropriate, but that seemed terribly inelegant. But then it dawned on him - all he needed to do was interfere with how Perl loaded modules.&lt;/p&gt;

&lt;p&gt;Normally the &lt;code&gt;@INC&lt;/code&gt; array is just a list of directories in which perl will look, one directory after another, for modules that you try to &lt;code&gt;use&lt;/code&gt;. But you can also put code-refs in it. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ perl -E &#38;#39;
    BEGIN { unshift @INC, sub { say &#38;quot;Hello World&#38;quot; } }
    use Foo;
  &#38;#39;
  Hello World
  [loud complaining from perl]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(NB the BEGIN block is required so that we get to diddle &lt;code&gt;@INC&lt;/code&gt; at compile- time. The complaining from perl is because &lt;code&gt;say&lt;/code&gt; returns something that perl doesn&#38;#39;t know what to do with)&lt;/p&gt;

&lt;p&gt;When Perl finds a code-ref in &lt;code&gt;@INC&lt;/code&gt; it passes the desired module to the code- ref, with its name reformatted from something like &lt;code&gt;Foo::Bar&lt;/code&gt; to a filename like &lt;code&gt;Foo/Bar.pm&lt;/code&gt;. Your code-ref can then decide not to do anything, thus making perl look in the next place listed in &lt;code&gt;@INC&lt;/code&gt;, or it can return the source code for a module:&lt;/p&gt;

&lt;p&gt;To have your sub-routine do nothing and have Perl carry on to the next entry in &lt;code&gt;@INC&lt;/code&gt; have it return &lt;code&gt;undef&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ perl -E &#38;#39;
    BEGIN { unshift @INC, sub { return undef } }
    use File::Temp;
  &#38;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That code-ref has absolutely no effect - when Perl tries to &lt;code&gt;use File::Temp&lt;/code&gt; it first executes our subroutine, which returns &lt;code&gt;undef&lt;/code&gt;, so Perl then tries to load it from the directories that make up the rest of the list, and eventually succeeds.&lt;/p&gt;

&lt;p&gt;So what if we want to prevent &lt;code&gt;File::Temp&lt;/code&gt; from loading? Our &lt;code&gt;@INC&lt;/code&gt; hook has to return an open filehandle which Perl can read the module code from, and the code we return (which Perl will then read and execute as if it were the &lt;code&gt;File::Temp&lt;/code&gt; module) should just die instead:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ perl -E &#38;#39;
    BEGIN { unshift @INC, sub {
      # is this what we&#38;#39;re hiding?  return an alternative file-handle
      if ($_[1] eq &#38;quot;File/Temp.pm&#38;quot;) {
        open my $fh, &#38;quot;&#38;lt;&#38;quot;, \&#38;quot;die(qq{$_[1] is hidden})&#38;quot;;
        return $fh;
      }

      # not something we&#38;#39;re hiding, return undef so Perl will continue as normal
      return undef;
    } }
    use File::Temp;
  &#38;#39;
  File/Temp.pm is hidden at /loader/0x7ffe498186e8/File/Temp.pm line 1.
  Compilation failed in require at -e line 8.
  BEGIN failed--compilation aborted at -e line 8.&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;PERL5OPT-and--M&#34;&gt;PERL5OPT and -M&lt;/h3&gt;

&lt;p&gt;Santa was very happy and wrapped this up in a module:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Without&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # translate a list of modules to a list of filenames&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@hidden&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;substitute&#34;&gt;s!::!/!g&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;$_.pm&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;unshift&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@INC&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # $_[0] is this sub-routine itself.&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$wanted&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;];&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$wanted&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@hidden&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;open&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$fh&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;&#38;lt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;die(qq{$wanted is hidden})&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$fh&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So that he could invoke like this to test his code with both RoboReindeer and BioReindeer, with one but not the other, and even without both:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  make test &#38;amp;&#38;amp;
  PERL5OPT=-MWithout=RoboReindeer             make test &#38;amp;&#38;amp;
  PERL5OPT=-MWithout=BioReindeer              make test &#38;amp;&#38;amp;
  PERL5OPT=-MWithout=RoboReindeer,BioReindeer make test&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;PERL5OPT is an environment variable that contains extra command line arguments that will be passed to any Perl process. -M is used to load a module on the command line, but using it to pass arguments to the module&#38;#39;s &lt;code&gt;import()&lt;/code&gt;method is less well known.&lt;/p&gt;

&lt;h3 id=&#34;A-few-days-later&#34;&gt;A few days later&lt;/h3&gt;

&lt;p&gt;Santa was very pleased with himself and later that week he went to his local Perl Mongers meeting, with his laptop, so that he could show everyone his nifty new trick.&lt;/p&gt;

&lt;p&gt;&#38;quot;Oh, you wanted &lt;a href=&#34;https://metacpan.org/module/Devel::Hide&#34;&gt;Devel::Hide&lt;/a&gt;&#38;quot;, they told him, adding that &lt;code&gt;PERL5OPT&lt;/code&gt; isn&#38;#39;t used in taint-mode and that the trick of using open to turn a scalar into a filehandle didn&#38;#39;t work in some really old perls.&lt;/p&gt;

&lt;p&gt;&#38;quot;Bother&#38;quot;, said Santa, as he deleted his code and installed Devel::Hide from the CPAN. &#38;quot;Ah well, it was fun anyway.&#38;quot;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  make test &#38;amp;&#38;amp;
  PERL5OPT=-MDevel::Hide=RoboReindeer             make test &#38;amp;&#38;amp;
  PERL5OPT=-MDevel::Hide=BioReindeer              make test &#38;amp;&#38;amp;
  PERL5OPT=-MDevel::Hide=RoboReindeer,BioReindeer make test&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h3&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Devel::Hide&#34;&gt;Devel::Hide&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For details on &lt;code&gt;PERL5OPT&lt;/code&gt; and &lt;code&gt;-M&lt;/code&gt;, see &lt;a href=&#34;https://metacpan.org/module/perlrun&#34;&gt;perlrun&lt;/a&gt;.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For details on magical @INC, see &lt;a href=&#34;https://metacpan.org/module/perlfunc#require&#34;&gt;&#38;quot;require&#38;quot; in perlfunc&lt;/a&gt;.&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-04T00:00:00Z</updated><category term="Perl"/><author><name>David Cantrell</name></author></entry><entry><title>Winter Platypus</title><link href="http://perladvent.org/2015/2015-12-03.html"/><id>http://perladvent.org/2015/2015-12-03.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;The boss (Mr. Claus) asked me to whip up some decorations for the Christmas party, and since this is a modern outfit (as you know we have the the largest toy and child database in the world), cutting some paper snowflakes just wasn&#38;#39;t going to impress.&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;screenshot800.png&#34;/&gt;&lt;/center&gt;

&lt;p&gt;I decided to write a little Perl program to render these three dimensional snowflakes and make them spin around on screen.&lt;/p&gt;

&lt;h3 id=&#34;Roles&#34;&gt;Roles&lt;/h3&gt;

&lt;p&gt;The first step was to create a class that represented a snowflake, and knew how to draw it. As the rendering of the snowflake is distinct from the actual attributes of the snowflake itself, I decided to create separate roles for the model and drawing code and combine these together in the end into one concrete snowflake class.&lt;/p&gt;

&lt;p&gt;So, starting with a model to represent the physical characteristics of each snowflake, using a Moose role:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SnowflakeModel&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose::Role&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;num_twigs&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Num&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;pinkie_length&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Num&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.5&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;2.0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;branch_length&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Num&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;segments&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Int&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;rw&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Num&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( x y z )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;rw&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Num&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( xspin yspin zspin )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The model keeps track of the number of branches, and twigs (it would be the &#38;quot;leaf&#38;quot; node, but this being a winter party the leaves have obviously fallen).&lt;/p&gt;

&lt;p&gt;The next step was to write some code to draw the snowflake. After some tweaking, I decided on a recursive algorithm using OpenGL.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SnowflakeDraw&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;5.010&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose::Role&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GLUT&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( &lt;br /&gt;&#38;nbsp;&#38;nbsp;num_twigs pinkie_length branch_length segments&lt;br /&gt;&#38;nbsp;&#38;nbsp;x y z xspin yspin zspin&lt;br /&gt;)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;draw_twig&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$base&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$height&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sides&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPushMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;-90.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glutSolidCone&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$base&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$height&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sides&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPopMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;draw_branch&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$left&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;//=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;segments&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPushMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPushMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_branch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_twig&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.025&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;-60&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_branch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_twig&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.025&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPopMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glTranslated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$left&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;.75&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_branch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$left&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$left&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;.75&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$segments&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPopMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;draw&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPushMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glTranslated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;z&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;xspin&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;yspin&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;zspin&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glEnable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_COLOR_MATERIAL&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glEnable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_BLEND&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glColor4d&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.60&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.86&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.35&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;num_twigs&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPushMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;360&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;num_twigs&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_branch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;pinkie_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;branch_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_twig&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.05&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;branch_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPopMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPushMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;90&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_branch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;pinkie_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;branch_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;90&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_branch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;pinkie_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;branch_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_twig&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.05&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;branch_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;-180&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_branch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;pinkie_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;branch_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;90&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_branch&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;pinkie_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;branch_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw_twig&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.05&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;branch_length&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.25&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPopMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glDisable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_BLEND&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glDisable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_COLOR_MATERIAL&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glPopMatrix&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OpenGL is a portable API for drawing 3D graphics with fancy effects. Now I can combine the model and the draw logic into a single Moose class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Snowflake&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;SnowflakeModel&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;SnowflakeDraw&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;spin&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$xdelta&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ydelta&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$zdelta&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;xspin&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;xspin&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$xdelta&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;yspin&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;yspin&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ydelta&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;zspin&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;zspin&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$zdelta&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&#38;#39;ve been working on this team for a number of years, and we have frequently had to switch vendors and change implementations many times for various projects. If I have to replace the OpenGL code in the future, this separation of concerns helps ease the transition because the model and draw logic are in separate files, reducing the temptation of mixing them.&lt;/p&gt;

&lt;h3 id=&#34;OpenGL-and-Perl&#34;&gt;OpenGL and Perl&lt;/h3&gt;

&lt;p&gt;In order to use the GL functions from Perl, I wrote a partial set of GL bindings for Perl using FFI. FFI is a technique for calling code in dynamic libraries from a scripting language like Perl without writing XS, which is tied closely to the internal implementation of Perl itself.&lt;/p&gt;

&lt;p&gt;We here at North Pole Inc. are big users of FFI because we don&#38;#39;t have many XS programmers, and we often need to call into libraries written in other languages which don&#38;#39;t have XS bindings yet. Last year we were using &lt;a href=&#34;https://metacpan.org/module/FFI::Raw&#34;&gt;FFI::Raw&lt;/a&gt;, which at the time was the only practical FFI available on CPAN.&lt;/p&gt;

&lt;p&gt;Over our long summer break this year, an aquatic mammal who was visiting from down under introduced us to &lt;a href=&#34;https://metacpan.org/module/FFI::Platypus&#34;&gt;FFI::Platypus&lt;/a&gt;. We liked it so much we have largely migrated to it for all of our existing FFI code. Here are my bindings for the base OpenGL library.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;FFI::Platypus&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;FFI::CheckLib&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( find_lib_or_die )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( Exporter )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# standard constants defined with Perl&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;constant&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_SMOOTH&lt;/span&gt;              &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x1D01&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_DEPTH_TEST&lt;/span&gt;          &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0B71&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_BLEND&lt;/span&gt;               &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0BE2&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_TRUE&lt;/span&gt;                &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_FALSE&lt;/span&gt;               &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_LIGHTING&lt;/span&gt;            &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0B50&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_LIGHT0&lt;/span&gt;              &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x4000&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_DIFFUSE&lt;/span&gt;             &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x1201&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_POSITION&lt;/span&gt;            &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x1203&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_COLOR_BUFFER_BIT&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x00004000&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_DEPTH_BUFFER_BIT&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x00000100&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_CULL_FACE&lt;/span&gt;           &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0B44&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_PROJECTION&lt;/span&gt;          &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x1701&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_MODELVIEW&lt;/span&gt;           &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x1700&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_SRC_ALPHA&lt;/span&gt;           &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0302&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_ONE_MINUS_SRC_ALPHA&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0303&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GL_COLOR_MATERIAL&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0B57&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# wire up FFI::Platypus directly to the binary OpenGL libraries&lt;br /&gt;# (using FFI::CheckLib to find them wherever they are on our system)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;FFI::Platypus&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lib&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;magic&#34;&gt;$^O&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;darwin&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;/System/Library/Frameworks/OpenGL.framework/Libraries/libGLU.dylib&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;/System/Library/Frameworks/GLUT.framework/GLUT&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;find_lib_or_die&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;lib&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;glut&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;find_lib_or_die&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;lib&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLU&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;find_lib_or_die&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;lib&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GL&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# declare named shortcuts for the in-built c-types&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;unsigned int&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;unsigned char&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLboolean&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;int&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLint&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;double&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;float[]&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLfloat_array&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;unsigned int&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLbitfield&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;int&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLsizei&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# declare the functions and how their parameters and return&lt;br /&gt;# values should be mapped to Perl scalars&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glShadeModel&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glEnable&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glDisable&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glPushMatrix&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glPopMatrix&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glFlush&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glRotated&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glTranslated&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glColor4d&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glColor3d&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glLightfv&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLfloat_array&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glClear&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLbitfield&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glScaled&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glClearColor&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;float&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;float&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;float&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;float&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glMatrixMode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glViewport&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLint&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLint&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLsizei&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLsizei&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glBlendFunc&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glLoadIdentity&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;gluPerspective&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# export those functions to the caller&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@EXPORT&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/^(gl|GL_)/i&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%GL::&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After the usual module imports, you can see the first thing that I&#38;#39;ve defined are a number of constants which are used by OpenGL. These constants are usually defined in C header (.h) files. This can be problematic if the constants change frequently, but so long as the library is stable and the implementers are not feeling cruel this can be okay.&lt;/p&gt;

&lt;p&gt;The next piece of code creates an instance of &lt;a href=&#34;https://metacpan.org/module/FFI::Platypus&#34;&gt;FFI::Platypus&lt;/a&gt; which we will use to create the bindings to the library:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;FFI::Platypus&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lib&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;magic&#34;&gt;$^O&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;darwin&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;/System/Library/Frameworks/OpenGL.framework/Libraries/libGLU.dylib&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;double&#34;&gt;&#38;quot;/System/Library/Frameworks/GLUT.framework/GLUT&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;find_lib_or_die&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;lib&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;glut&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;find_lib_or_die&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;lib&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLU&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;find_lib_or_die&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;lib&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GL&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We need to tell Platypus which dynamic libraries to search in order to find functions, so we are using &lt;a href=&#34;https://metacpan.org/module/FFI::CheckLib&#34;&gt;FFI::CheckLib&lt;/a&gt;, which is a portable way of searching for libraries in the usual system locations. It provides a similar interface to the like-named &lt;a href=&#34;https://metacpan.org/module/Devel::CheckLib&#34;&gt;Devel::CheckLib&lt;/a&gt;, but is smarter about finding &lt;i&gt;dynamic&lt;/i&gt; libraries. We have a mixed environment of OS X and Linux for toy deliveries and testing, so it had to work on both platforms. Although &lt;a href=&#34;https://metacpan.org/module/FFI::CheckLib&#34;&gt;FFI::CheckLib&lt;/a&gt; generally works well in Windows, Linux, OS X (and others), the OpenGL libraries on OS X are part of what they call a &#38;quot;framework&#38;quot;, which isn&#38;#39;t supported by &lt;a href=&#34;https://metacpan.org/module/FFI::CheckLib&#34;&gt;FFI::CheckLib&lt;/a&gt; yet, so I hard coded the location of the libraries on that platform.&lt;/p&gt;

&lt;p&gt;The next part of the code defines the types used by the library:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;unsigned int&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This line defines &lt;code&gt;GLenum&lt;/code&gt; used throughout the GL library. Although you could just use &lt;code&gt;&#38;#39;unsigned int&#38;#39;&lt;/code&gt; throughout your code where GLenum is called for, this makes my code more readable, and it is easier to fix the type in one place if I make a mistake with &lt;code&gt;GLenum&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In general, the type system for Platypus is a bit different than other FFI implementations that I&#38;#39;ve used. Instead of providing only basic hardware types like &#38;quot;sixteen bit signed integer&#38;quot;, Platypus encourages the use of language and platform specific types--typically the same types that are understood by your library interface specifications (In C the header file). For example &lt;code&gt;long&lt;/code&gt; is a 32 or 64 bit signed integer depending on your platform and &lt;code&gt;char&lt;/code&gt; might be either signed or unsigned! You can even tell Platypus that you are working with Fortran or Rust and use the native types of those languages in your bindings.&lt;/p&gt;

&lt;p&gt;Finally in the meat of the module we attach the functions from the library into the GL namespace:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glEnable&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# which is called thusly:&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;glEnable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_LIGHT0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;attach&lt;/code&gt; method takes a function defined in the dynamic library and attaches it as a real Perl subroutine. The advantage to this approach is that the code that calls our GL library doesn&#38;#39;t need to know or care that it is using an FFI implementation or an XS one. It just looks like Perl.&lt;/p&gt;

&lt;p&gt;I needed some higher level types, like arrays (Platypus supports a number of higher level types like this):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;float[]&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLfloat_array&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glLightfv&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLenum&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLfloat_array&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glLightfv&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_LIGHT0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL_DIFFUSE&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;.9&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;.9&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glLightfv&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_LIGHT0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL_POSITION&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To do this sort of thing, many FFI implementations require you to create an array object and pass that in as an argument. Unfortunately there is an overhead to creating objects for single use calls like this, and it also exposes unnecessary complexity to your caller.&lt;/p&gt;

&lt;p&gt;Finally, this module uses Exporter to export all of its functions to the caller&#38;#39;s namespace:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( Exporter )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@EXPORT&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/^(gl|GL_)/i&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%GL::&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Many libraries implement hundreds of functions and keeping &lt;code&gt;@EXPORT&lt;/code&gt; in sync with functions as we add them is very tedious. Instead we use &lt;code&gt;%GL::&lt;/code&gt; which is a special hash that keeps track of the data structures (including subroutines) in the GL namespace. It has to be put at the bottom of the module because &lt;code&gt;%GL::&lt;/code&gt; won&#38;#39;t be populated until the &lt;code&gt;attach&lt;/code&gt; calls are made.&lt;/p&gt;

&lt;p&gt;The last module we need provides the Glut bindings. Glut provides a simple and portable OpenGL focused event loop for applications that do not require anything more complicated.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GLUT&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;5.010&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( Exporter )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;constant&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GLUT_RGB&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0000&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GLUT_DOUBLE&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0002&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;GLUT_DEPTH&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;hex&#34;&gt;0x0010&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$GL::ffi&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;load_custom_type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;FFI::Platypus::Type::StringArray&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;string_array&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutInit&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;int*&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;string_array&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;scalar&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutInitDisplayMode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;unsigned int&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutInitWindowSize&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;int&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;int&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutCreateWindow&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;string&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;       &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;int&#39;&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutMainLoop&lt;/span&gt;        &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutSwapBuffers&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutPostRedisplay&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutSolidCone&lt;/span&gt;        &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLdouble&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;GLint&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;GLint&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutDisplayFunc&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;()-&#38;gt;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$callback&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$closure&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;closure&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$callback&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$closure&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutIdleFunc&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;()-&#38;gt;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$callback&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$closure&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;closure&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$callback&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$closure&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutReshapeFunc&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;(int,int)-&#38;gt;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$callback&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$closure&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;closure&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$callback&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$closure&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@EXPORT&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/^(GLUT_|glut)/i&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%GLUT::&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things are interesting here. Firstly, the &lt;code&gt;glutInit()&lt;/code&gt; takes an array of C strings as its second argument.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;load_custom_type&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;FFI::Platypus::Type::StringArray&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;string_array&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutInit&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;int*&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;string_array&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;scalar&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Platypus&#38;#39; type system provides most of the common basic types that you will need. A few more specialized types, like arrays of C strings require the use of custom types. Here we are using &lt;a href=&#34;https://metacpan.org/module/FFI::Platypus::Type::StringArray&#34;&gt;FFI::Platypus::Type::StringArray&lt;/a&gt; which is frequently useful and available on CPAN, but not part of the Platypus core.&lt;/p&gt;

&lt;p&gt;Also interesting here is that we are using a wrapper (the last argument to the &lt;code&gt;attach&lt;/code&gt;) call. This is to hide some of the messy differences between C and Perl. In C when you pass a dynamic array into a function you have to provide the size of the array as an additional parameter. In Perl, arrays already know how many elements they have. Basically the above code is a short cut for this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutInit&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_glutInit&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;int*&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;string_array&#39;&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutInit&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;scalar&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;_glutInit&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this second version we attach &lt;code&gt;glutInit&lt;/code&gt; with a different name in Perl and call it from the &#38;quot;real&#38;quot; &lt;code&gt;glutInit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also the size of the array is passed in as a pointer to an integer so that Glut can alter its value. Although in this particular case we ignore any changes made by Glut, the scalar &lt;code&gt;$size&lt;/code&gt; &lt;b&gt;is&lt;/b&gt; updated if &lt;code&gt;glutInit&lt;/code&gt; makes a change. This is frequently useful, because a common pattern in C is to pass variables by reference by passing a pointer to that variable.&lt;/p&gt;

&lt;p&gt;The last thing that I want to point out is the use of closures:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attach&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;glutDisplayFunc&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;()-&#38;gt;void&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;void&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$callback&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$closure&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ffi&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;closure&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$callback&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$xsub&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$closure&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or calling back into Perl from C. This is extremely useful, but it is also a little tricky, because of the different ways that Perl and C manage memory. In C you must explicitly allocate and deallocate all memory. The convention is that the module that allocates a particular object will be responsible for deallocating it as well. In Perl the language itself takes responsibility for deallocating objects when they are no longer used anywhere in the Perl runtime. Unfortunately when we create a closure and pass it into Glut code, there is no way for Perl to keep track of whether or not the closure is still in use by Glut! In order to prevent Perl from reclaiming the subroutine before Glut is done with it, I save the closure into a &lt;code&gt;state&lt;/code&gt; variable, which will keep it in scope for the life of the program.&lt;/p&gt;

&lt;h3 id=&#34;Bringing-It-All-Together&#34;&gt;Bringing It All Together&lt;/h3&gt;

&lt;p&gt;Now that we have all the ingredients, we can write out main script:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GLUT&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Snowflake&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glutInit&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@ARGV&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glutInitDisplayMode&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GLUT_DOUBLE&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GLUT_RGB&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GLUT_DEPTH&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glutInitWindowSize&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1500&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;500&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glutCreateWindow&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;snowflake&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glLightfv&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_LIGHT0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL_DIFFUSE&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;.9&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;.9&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glLightfv&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_LIGHT0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL_POSITION&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glEnable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_LIGHT0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glEnable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_LIGHTING&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glEnable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_CULL_FACE&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glShadeModel&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_SMOOTH&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glClearColor&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glBlendFunc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_SRC_ALPHA&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL_ONE_MINUS_SRC_ALPHA&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glEnable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_DEPTH_TEST&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@flakes&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Snowflake&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;z&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;-5.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;2.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;-2.0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;display&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glClear&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_COLOR_BUFFER_BIT&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GL_DEPTH_BUFFER_BIT&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glLoadIdentity&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;draw&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@flakes&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glFlush&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glutSwapBuffers&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;idle&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$flakes&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;spin&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.6&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$flakes&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;spin&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.6&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$flakes&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;spin&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.6&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glutPostRedisplay&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;reshape&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$x&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$y&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$x&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$y&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glMatrixMode&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_PROJECTION&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glLoadIdentity&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;gluPerspective&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;float&#34;&gt;30.0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$x&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$y&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;20.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glMatrixMode&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GL_MODELVIEW&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;glViewport&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$x&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$y&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glutDisplayFunc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;&#38;amp;display&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glutIdleFunc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;&#38;amp;idle&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glutReshapeFunc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;&#38;amp;reshape&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;glutMainLoop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that thanks to the care of &lt;a href=&#34;https://metacpan.org/module/FFI::Platypus&#34;&gt;FFI::Platypus&lt;/a&gt; and a few wrappers in the &lt;code&gt;GLUT&lt;/code&gt; module, our main script doesn&#38;#39;t have to know or care that it is using FFI.&lt;/p&gt;

&lt;p&gt;I have three pretty snowflakes for the holiday party.&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;screenshot800.png&#34;/&gt;&lt;/center&gt;

&lt;p&gt;My coworker android friend Mr. Lore also enjoyed it since it reminded him of his friend The Crystalline Entity.&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/FFI::Platypus&#34;&gt;FFI::Platypus&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/FFI::CheckLib&#34;&gt;FFI::CheckLib&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/FFI::Raw&#34;&gt;FFI::Raw&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.opengl.org/&#34;&gt;https://www.opengl.org/&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-03T00:00:00Z</updated><category term="Perl"/><author><name>Graham Ollis</name></author></entry><entry><title>Fast CPAN Module Installation</title><link href="http://perladvent.org/2015/2015-12-02.html"/><id>http://perladvent.org/2015/2015-12-02.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;&#38;quot;This build is taking &lt;i&gt;forever&lt;/i&gt;&#38;quot;, complained Cookie Cutter, the newest elf to join Santa&#38;#39;s Continuous Integration team, &#38;quot;We&#38;#39;ll be lucky if it&#38;#39;s done by &lt;i&gt;next&lt;/i&gt; Christmas, let alone this one!&#38;quot;.&lt;/p&gt;

&lt;p&gt;&#38;quot;Well, we do use a &lt;i&gt;lot&lt;/i&gt; of CPAN modules&#38;quot;, Snowstorm, head of the team, explained. &#38;quot;They take a while to install on a new machine, but we&#38;#39;re certainly not going to re-write all that code ourselves. I just wish it would install quicker.&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;Well,&#38;quot; Cookie Cutter smiled, &#38;quot;I might have a way...&#38;quot;&lt;/p&gt;

&lt;h3 id=&#34;Solving-Cookie-Cutters-Problem&#34;&gt;Solving Cookie Cutter&#38;#39;s Problem&lt;/h3&gt;

&lt;p&gt;I write Perl everyday with great CPAN modules.&lt;/p&gt;

&lt;p&gt;To install modules from the CPAN, I was using &lt;a href=&#34;https://metacpan.org/module/cpanm&#34;&gt;cpanm&lt;/a&gt;. I love it because it just works. One command not only installs the module, but first installs all the dependencies of that module that aren&#38;#39;t already installed, and all the dependencies of those modules, and so on and so on&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   shell&#38;gt; cpanm Catalyst&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you develop a serious Perl software, it often depends on hundreds of CPAN modules. In fact, dependence on Catalyst implies dependence on 100+ CPAN modules at least.&lt;/p&gt;

&lt;p&gt;Because of this it can take quite a lot of time to install a module with &lt;code&gt;cpanm&lt;/code&gt;. This is because &lt;code&gt;cpanm&lt;/code&gt; installs them in series, downloading one and examining one module at a time.&lt;/p&gt;

&lt;p&gt;Like Cookie Cutter, I always hoped I could install CPAN modules faster.&lt;/p&gt;

&lt;p&gt;In Perl QA Hackathon 2015, Tatsuhiko Miyagawa, the author of &lt;code&gt;cpanm&lt;/code&gt;, developed Menlo (the code name of cpanm 2.0). And he announced that Menlo would be maintained and released as a regular Perl module in &lt;a href=&#34;http://weblog.bulknews.net/post/117034550339/cpanm-towards-20-menlo&#34;&gt;his blog post&lt;/a&gt;. This allows us to write Perl code that depends on Menlo. This is exciting, isn&#38;#39;t it?&lt;/p&gt;

&lt;p&gt;Using Menlo I was finally able to write a CPAN module installer called &lt;code&gt;cpm&lt;/code&gt; which installed in parallel. Rather than downloading one module and examining each module one at a time like &lt;code&gt;cpanm&lt;/code&gt; does, as soon as &lt;code&gt;cpm&lt;/code&gt; has identified multiple dependencies it starts download and install more than one module at once. This parallelism makes &lt;code&gt;cpm&lt;/code&gt; faster than any other CPAN module installer.&lt;/p&gt;

&lt;h3 id=&#34;Are-you-sure-cpm-is-fast&#34;&gt;Are you sure cpm is fast?&lt;/h3&gt;

&lt;p&gt;As &lt;code&gt;cpm&lt;/code&gt; is a module just like any other on the CPAN, its installation is straightforward:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   $ cpanm App::cpm&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now you have &lt;code&gt;cpm&lt;/code&gt;! Let&#38;#39;s try installing Plack with both &lt;code&gt;cpanm&lt;/code&gt; and &lt;code&gt;cpm&lt;/code&gt;, and compare their elapsed times. Because &lt;code&gt;cpm&lt;/code&gt; does not run test cases, we need to execute &lt;code&gt;cpanm&lt;/code&gt; with &lt;code&gt;--notest&lt;/code&gt; option in order to get a fair test:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   $ time cpanm -L extlib --notest --quiet Plack
   ...
   real    0m47.705s&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next cpm:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   $ time cpm install Plack
   ...
   real    0m16.629s&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wow, this shows cpm (16sec) is about 3 times faster than cpanm (47sec)!&lt;/p&gt;

&lt;center&gt;&lt;img src=&#34;cpm.png&#34; width=&#34;460&#34; height=&#34;321&#34;&gt;&lt;/center&gt;

&lt;p&gt;Of course results will change depending on the situation, so why don&#38;#39;t you try it yourself?&lt;/p&gt;

&lt;h3 id=&#34;TODO&#34;&gt;TODO&lt;/h3&gt;

&lt;p&gt;In YAPC::Asia 2015, I could talked with miyagawa about cpanm. Then he said the parallel feature might be merged into cpanm itself. I was really happy to hear that.&lt;/p&gt;

&lt;p&gt;To merge cpm into cpanm, there are some TODOs or issues that must be resolved:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;cpm&lt;/code&gt; will need to support platforms that do not have fork(2) system call. Currently &lt;code&gt;cpm&lt;/code&gt; doesn&#38;#39;t work on such platforms.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Messy log output (a big issue!) Currently cpm uses Menlo in parallel and the outputs of all the Menlos are just redirected to one file. So outputs are mixed and really messy. I believe the logging is important for stable software. Do you accept the messiness, or do you have any ideas to resolve this?&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;Meanwhile-back-at-the-North-Pole&#34;&gt;Meanwhile, back at the North Pole...&lt;/h3&gt;

&lt;p&gt;&#38;quot;You see&#38;quot;, said Cookie Cutter, &#38;quot;cpm is a CPAN module installer which is faster than other CPAN module installers.&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;And we can install it just with &#38;#39;cpanm App::cpm&#38;#39;?&#38;quot;, asked Snowstorm, &#38;quot;That&#38;#39;s it?&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;Yep! All we need to do is change one line in our installer script to start using it. And hopefully if we and other people find cpm useful and stable, then it may be merged into cpanm itself!&#38;quot;&#38;quot;&lt;/p&gt;

&lt;h3 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h3&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/App::cpm&#34;&gt;App::cpm&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/App::cpanminus&#34;&gt;App::cpanminus&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Menlo&#34;&gt;Menlo&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-02T00:00:00Z</updated><category term="Perl"/><author><name>Shoichi Kaji</name></author></entry><entry><title>Where in the World?</title><link href="http://perladvent.org/2015/2015-12-01.html"/><id>http://perladvent.org/2015/2015-12-01.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Santa had a problem, and the problem was &lt;i&gt;kids&lt;/i&gt;. Not that he didn&#38;#39;t love the children - far from it, their happiness was why he did what he did after all - but now there were more than ever of them. World population had grown to the point where there were 2.2 billion children who potentially wanted a gift, and that was a lot of mince pies to get through in one night!&lt;/p&gt;

&lt;p&gt;To ensure that he&#38;#39;d have time to make all the deliveries he&#38;#39;d taken the unprecedented step of installing agents in homes around the world - elves that sat on shelves - who were able to report on any problem, from waking children to adverse weather conditions, that might slow him down. Traditionally a Shelf Elf would report by flying home each night leading up to Christmas, but on the big night itself the elf would have to report back in real time. Luckily for Santa, so many houses had internet connections that the Elf could use to report issues via a simple web form the Wise Old Elf had set up on the North Pole extranet.&lt;/p&gt;

&lt;p&gt;This is where our hero Candy Cane comes in. Candy Cane sighed as he read the story in the latest Elf development sprint: &#38;quot;A proof of concept exists that displays the Shelf Elf reports on a map so that Central Elf Command can coordinate them as Santa moves around the world&#38;quot;. 2 points.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Should be straight forward&lt;/i&gt;, thought Candy Cane to himself, &lt;i&gt;We agreed in estimation that all I have to do is take the location from each report and feed it to the MapBox JavaScript library, and we&#38;#39;ll have a nice map. Easy peasy&lt;/i&gt;. With Elf joy in his heart from working on something he loved, he opened up the database schema to see how to get the location from the reports table.&lt;/p&gt;

&lt;p&gt;The joy was short lived. With a sinking heart Candy realized that the reports didn&#38;#39;t actually contain a location. They just contained the child&#38;#39;s name the Elf was responsible for: fine for giving to the magical reindeer who instinctively knew the way to every chimney top, but useless for plotting on a map.&lt;/p&gt;

&lt;p&gt;The elf cast his gaze over the other columns, trying to figure out what to do, when his eyes settled on the IP address that the report was submitted from. &lt;i&gt;Hmmm&lt;/i&gt;, he thought, &lt;i&gt;just maybe...&lt;/i&gt;&lt;/p&gt;

&lt;h3 id=&#34;GeoIP2&#34;&gt;GeoIP2&lt;/h3&gt;

&lt;p&gt;GeoIP2 is the Perl interface to the MaxMind geolocation services, providing a way to map an IP address to, amongst other things, a physical location in the world - perfect for plotting Elf reports on a map based on an IP address alone. MaxMind provides the GeoLite2 databases which anyone can periodically download for free from their website to do offline geolocation.&lt;/p&gt;

&lt;p&gt;From Perl this is relatively straight forward to use. First create the reader with the database:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$reader&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GeoIP2::Database::Reader&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;file&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$MMDB_DATABASE_LOCATION&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;locales&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;en&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then do a lookup on an IP address:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# lookup where the IP is with the &#38;quot;city&#38;quot; level of precision&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$where&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$reader&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;city&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ip&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From this model you can ask for various things, for example the location of the IP:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$location&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$where&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;location&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$lat&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$long&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$location&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;latitude&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$location&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;longitude&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or information on the nearest city:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$nearest_city&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$where&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;city&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$city_name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$nearest_city&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All kinds of things that you can render on a map.&lt;/p&gt;

&lt;h3 id=&#34;MapBox&#34;&gt;MapBox&lt;/h3&gt;

&lt;p&gt;Once the hard work is out of the way, Candy Cane had the relatively simple job of rendering the reports on a map. While a complicated version would come later, Candy decided for the proof of concept a simple Mojolicious::Lite application that used the MapBox API would be sufficient:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/perl&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Mojolicious::Lite&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;5.18.0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GeoIP2::Database::Reader&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File::Spec::Functions&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(:ALL)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File::Basename&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(dirname)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$MAPBOX_TOKEN&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;pk.eyJ1IjoiMnNob3J0cGxhbmzzIiwiYSI6ImNpZmw1ZzdnMTV5aXBpdWx4dDhpbjF6ZGQifQ.C3lPhZeBCapfVSQhpcGsLA&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$MMDB_DATABASE_LOCATION&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;catfile&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;dirname&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;__FILE__&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;GeoLite2-City.mmdb&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;   &lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;report_to_point&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$report&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$reader&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GeoIP2::Database::Reader&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;file&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$MMDB_DATABASE_LOCATION&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;locales&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;en&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # lookup where the IP is with the &#38;quot;city&#38;quot; level of precision&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$where&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$reader&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;city&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$report&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # define a &#38;quot;point feature&#38;quot; data structure that MapBox understands&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Feature&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;properties&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;title&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$where&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;city&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$report&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;geometry&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Point&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;coordinates&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$where&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;location&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;longitude&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$where&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;location&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;latitude&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;get&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;/&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # get the reports from the database, and turn them into mapbox &#38;quot;points&#38;quot;&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$pg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Mojo::Pg&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;postgresql://postgres@/test&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$features&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$pg&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;db&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;query&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;SELECT * FROM reports&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;hashes&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;report_to_point&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;features&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$features&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;token&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$MAPBOX_TOKEN&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;index&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;separator&#34;&gt;__DATA__&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;data&#34;&gt;&lt;br /&gt;@@ index.html.ep&lt;br /&gt;% use Mojo::JSON qw(to_json);&lt;br /&gt;&#38;lt;!DOCTYPE html&#38;gt;&lt;br /&gt;&#38;lt;html&#38;gt;&lt;br /&gt;&#38;lt;head&#38;gt;&lt;br /&gt;&#38;lt;meta charset=utf-8 /&#38;gt;&lt;br /&gt;&#38;lt;title&#38;gt;Shelf Elf Reports&#38;lt;/title&#38;gt;&lt;br /&gt;&#38;lt;meta name=&#39;viewport&#39; content=&#39;initial-scale=1,maximum-scale=1,user-scalable=no&#39; /&#38;gt;&lt;br /&gt;&#38;lt;script src=&#39;https://api.mapbox.com/mapbox.js/v2.2.2/mapbox.js&#39;&#38;gt;&#38;lt;/script&#38;gt;&lt;br /&gt;&#38;lt;link href=&#39;https://api.mapbox.com/mapbox.js/v2.2.2/mapbox.css&#39; rel=&#39;stylesheet&#39; /&#38;gt;&lt;br /&gt;&#38;lt;style&#38;gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;body { margin:0; padding:0; }&lt;br /&gt;&#38;nbsp;&#38;nbsp;#map { position:absolute; top:0; bottom:0; width:100%; }&lt;br /&gt;&#38;lt;/style&#38;gt;&lt;br /&gt;&#38;lt;/head&#38;gt;&lt;br /&gt;&#38;lt;body&#38;gt;&lt;br /&gt;&#38;lt;div id=&#39;map&#39;&#38;gt;&#38;lt;/div&#38;gt;&lt;br /&gt;&#38;lt;script&#38;gt;&lt;br /&gt;L.mapbox.accessToken = &#39;&#38;lt;%= $token %&#38;gt;&#39;;&lt;br /&gt;&lt;br /&gt;var map = L.mapbox.map(&#39;map&#39;, &#39;mapbox.light&#39;).setView([29, -26], 2);&lt;br /&gt;&lt;br /&gt;var myLayer = L.mapbox.featureLayer().addTo(map);&lt;br /&gt;myLayer.setGeoJSON({&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;type: &#39;FeatureCollection&#39;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;features: &#38;lt;%== to_json $features %&#38;gt;&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;&#38;lt;/script&#38;gt;&lt;br /&gt;&#38;lt;/body&#38;gt;&lt;br /&gt;&#38;lt;/html&#38;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;Wait till Santa sees this&lt;/i&gt; thought Candy, laughing to himself how he&#38;#39;d managed to get the map working despite not having what anyone would have traditionally thought of as location data. Santa wouldn&#38;#39;t be asking &lt;i&gt;where in the world?&lt;/i&gt; the problems were anymore, but he probably would be asking &lt;i&gt;where in the world?&lt;/i&gt; had Candy got the brilliant idea to use IP Geolocation.&lt;/p&gt;

&lt;h2 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/pod/GeoIP2::Database::Reader&#34;&gt;https://metacpan.org/pod/GeoIP2::Database::Reader&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://dev.maxmind.com/geoip/geoip2/geolite2/&#34;&gt;http://dev.maxmind.com/geoip/geoip2/geolite2/&lt;/a&gt; offers download of the GeoLite2 databases&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2015-12-01T00:00:00Z</updated><category term="Perl"/><author><name>Mark Fowler</name></author></entry></feed>