Sorry

This feed does not validate.

In addition, interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: https://rhnh.net/feed.xml

  1. <?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xml" href="http://localhost:4000/feed.xslt.xml"?><feed xmlns="http://www.w3.org/2005/Atom"><generator uri="http://jekyllrb.com" version="3.3.1">Jekyll</generator><link href="http://localhost:4000/feed.xml" rel="self" type="application/atom+xml" /><link href="http://localhost:4000/" rel="alternate" type="text/html" /><updated>2019-05-30T02:31:35+00:00</updated><id>http://localhost:4000//</id><entry><title type="html">One Way to Reset a Macbook Password</title><link href="http://localhost:4000/2019/05/30/one-way-to-reset-a-stuck-macbook-password/" rel="alternate" type="text/html" title="One Way to Reset a Macbook Password" /><published>2019-05-30T00:00:00+00:00</published><updated>2019-05-30T00:00:00+00:00</updated><id>http://localhost:4000/2019/05/30/one-way-to-reset-a-stuck-macbook-password</id><content type="html" xml:base="http://localhost:4000/2019/05/30/one-way-to-reset-a-stuck-macbook-password/">&lt;p&gt;Weird problem today: macbook was accepting my password to decrypt disk, but not
  2. accepting it for user account login. This started happening after adding lock
  3. button to my touch bar. I can’t see how that’s related, but that was the last
  4. thing I did so maybe relevant!? Tried the new button, locked my computer,
  5. couldn’t login again.&lt;/p&gt;
  6.  
  7. &lt;p&gt;Things that didn’t work:&lt;/p&gt;
  8.  
  9. &lt;ul&gt;
  10.  &lt;li&gt;Reset password using recovery key. (I think this only resets the disk password?)&lt;/li&gt;
  11.  &lt;li&gt;Recovery mode (hold &lt;code&gt;Command+R&lt;/code&gt; on boot), &lt;code&gt;resetpassword&lt;/code&gt; in terminal. Weirdly
  12. this did change the password hint for the account, but the new password was
  13. still not accepted.&lt;/li&gt;
  14.  &lt;li&gt;Reseting PRAM (hold &lt;code&gt;Command+Option+P+R&lt;/code&gt; on boot).&lt;/li&gt;
  15. &lt;/ul&gt;
  16.  
  17. &lt;p&gt;What did work (thanks to Apple care phone support, very good experience):&lt;/p&gt;
  18.  
  19. &lt;ol&gt;
  20.  &lt;li&gt;Boot into recovery mode (hold &lt;code&gt;Command+R&lt;/code&gt; on boot).&lt;/li&gt;
  21.  &lt;li&gt;Open &lt;code&gt;Disk Utilities&lt;/code&gt; and mount &lt;code&gt;Macintosh HD&lt;/code&gt;.&lt;/li&gt;
  22.  &lt;li&gt;Open &lt;code&gt;Terminal&lt;/code&gt; and &lt;code&gt;rm /Volumes/Macintosh\ HD/var/db/.AppleSetupDone&lt;/code&gt;.&lt;/li&gt;
  23.  &lt;li&gt;Reboot computer, enter disk password, then go through new computer setup
  24. again.&lt;/li&gt;
  25.  &lt;li&gt;When prompted, create a new &lt;code&gt;Temp Admin&lt;/code&gt; user account. You’ll end up logged
  26. in as this new temp admin.&lt;/li&gt;
  27.  &lt;li&gt;Via System Settings, User &amp;amp; Accounts, reset password of your original account.&lt;/li&gt;
  28.  &lt;li&gt;Log out and re-login as your original account (hooray!)&lt;/li&gt;
  29.  &lt;li&gt;Delete the newly created &lt;code&gt;Temp Admin&lt;/code&gt; account.&lt;/li&gt;
  30. &lt;/ol&gt;</content><category term="it" /><summary type="html">Weird problem today: macbook was accepting my password to decrypt disk, but not
  31. accepting it for user account login. This started happening after adding lock
  32. button to my touch bar. I can’t see how that’s related, but that was the last
  33. thing I did so maybe relevant!? Tried the new button, locked my computer,
  34. couldn’t login again.</summary></entry><entry><title type="html">Migrating from TSlime and Vim to VSCode</title><link href="http://localhost:4000/2019/04/25/migrating-from-tslime-and-vim-to-vscode/" rel="alternate" type="text/html" title="Migrating from TSlime and Vim to VSCode" /><published>2019-04-25T00:00:00+00:00</published><updated>2019-04-25T00:00:00+00:00</updated><id>http://localhost:4000/2019/04/25/migrating-from-tslime-and-vim-to-vscode</id><content type="html" xml:base="http://localhost:4000/2019/04/25/migrating-from-tslime-and-vim-to-vscode/">&lt;p&gt;I’m trying out VSCode. It’s pretty good. Using the Vim extension, I can
  35. recreate my &lt;a href=&quot;/2011/08/20/vim-and-tmux-on-osx/&quot;&gt;tslime workflow&lt;/a&gt; giving me one
  36. command save-cancel-rerun behaviour in the integrated terminal. In
  37. &lt;code&gt;Preferences -&amp;gt; Settings&lt;/code&gt;, and JSON edit mode, add the following to the
  38. existing:&lt;/p&gt;
  39.  
  40. &lt;div class=&quot;language-json highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  41.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt; 1&lt;/span&gt; {
  42. &lt;span class=&quot;no&quot;&gt; 2&lt;/span&gt;     &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;vim.leader&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
  43. &lt;span class=&quot;no&quot;&gt; 3&lt;/span&gt;     &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;vim.normalModeKeyBindingsNonRecursive&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [
  44. &lt;span class=&quot;no&quot;&gt; 4&lt;/span&gt;         {
  45. &lt;span class=&quot;no&quot;&gt; 5&lt;/span&gt;             &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;before&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;&amp;lt;leader&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;],
  46. &lt;span class=&quot;no&quot;&gt; 6&lt;/span&gt;             &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;after&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [],
  47. &lt;span class=&quot;no&quot;&gt; 7&lt;/span&gt;             &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;commands&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [
  48. &lt;span class=&quot;no&quot;&gt; 8&lt;/span&gt;                 {
  49. &lt;span class=&quot;no&quot;&gt; 9&lt;/span&gt;                     &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;command&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;workbench.action.quickOpen&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  50. &lt;span class=&quot;no&quot;&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;                 }
  51. &lt;span class=&quot;no&quot;&gt;11&lt;/span&gt;             ],
  52. &lt;span class=&quot;no&quot;&gt;12&lt;/span&gt;         },
  53. &lt;span class=&quot;no&quot;&gt;13&lt;/span&gt;         {
  54. &lt;span class=&quot;no&quot;&gt;14&lt;/span&gt;             &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;before&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;&amp;lt;leader&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;],
  55. &lt;span class=&quot;no&quot;&gt;15&lt;/span&gt;             &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;after&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [],
  56. &lt;span class=&quot;no&quot;&gt;16&lt;/span&gt;             &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;commands&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [
  57. &lt;span class=&quot;no&quot;&gt;17&lt;/span&gt;                 {
  58. &lt;span class=&quot;no&quot;&gt;18&lt;/span&gt;                     &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;command&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;workbench.action.files.save&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  59. &lt;span class=&quot;no&quot;&gt;19&lt;/span&gt;                 },
  60. &lt;span class=&quot;no&quot;&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt;                 {
  61. &lt;span class=&quot;no&quot;&gt;21&lt;/span&gt;                     &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;command&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;workbench.action.terminal.sendSequence&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
  62. &lt;span class=&quot;no&quot;&gt;22&lt;/span&gt;                     &lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;args&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: {&lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;text&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#b0b&quot;&gt;\u0003&lt;/span&gt;&lt;span style=&quot;&quot;&gt;!!&lt;/span&gt;&lt;span style=&quot;color:#b0b&quot;&gt;\u000d&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}
  63. &lt;span class=&quot;no&quot;&gt;23&lt;/span&gt;                 }
  64. &lt;span class=&quot;no&quot;&gt;24&lt;/span&gt;             ]
  65. &lt;span class=&quot;no&quot;&gt;25&lt;/span&gt;         }
  66. &lt;span class=&quot;no&quot;&gt;26&lt;/span&gt;     ],
  67. &lt;span class=&quot;no&quot;&gt;27&lt;/span&gt; }
  68. &lt;/pre&gt;&lt;/div&gt;
  69. &lt;/div&gt;
  70. &lt;/div&gt;
  71.  
  72. &lt;p&gt;Also includes a cheeky &lt;code&gt;&amp;lt;leader&amp;gt;p&lt;/code&gt; binding to replace &lt;code&gt;command+P&lt;/code&gt; for quick
  73. open since it’s more ergonomic on my layout. Relevant documentation:&lt;/p&gt;
  74.  
  75. &lt;ul&gt;
  76.  &lt;li&gt;&lt;a href=&quot;https://github.com/VSCodeVim/Vim&quot;&gt;Vim extension README&lt;/a&gt; for overall configuration primer.&lt;/li&gt;
  77.  &lt;li&gt;&lt;a href=&quot;https://github.com/VSCodeVim/Vim/issues/2552#issuecomment-384401284&quot;&gt;Vim extension issue
  78. comment&lt;/a&gt;
  79. with exact incantation for remapping quick open.&lt;/li&gt;
  80.  &lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/docs/getstarted/keybindings&quot;&gt;VSCode default
  81. keybindings&lt;/a&gt; for
  82. finding out that &lt;code&gt;command+S&lt;/code&gt; is actually &lt;code&gt;workbench.action.files.save&lt;/code&gt;.&lt;/li&gt;
  83. &lt;/ul&gt;</content><category term="code" /><category term="vscode" /><summary type="html">I’m trying out VSCode. It’s pretty good. Using the Vim extension, I can
  84. recreate my tslime workflow giving me one
  85. command save-cancel-rerun behaviour in the integrated terminal. In
  86. Preferences -&amp;gt; Settings, and JSON edit mode, add the following to the
  87. existing:</summary></entry><entry><title type="html">Using Size to Debug D3 Selections</title><link href="http://localhost:4000/2018/10/21/debugging-d3-selections/" rel="alternate" type="text/html" title="Using Size to Debug D3 Selections" /><published>2018-10-21T00:00:00+00:00</published><updated>2018-10-21T00:00:00+00:00</updated><id>http://localhost:4000/2018/10/21/debugging-d3-selections</id><content type="html" xml:base="http://localhost:4000/2018/10/21/debugging-d3-selections/">&lt;p&gt;Yesterday I was learning about the relatively new &lt;a href=&quot;https://bl.ocks.org/mbostock/3808218&quot;&gt;General Update
  88. Pattern&lt;/a&gt; in D3, but I couldn’t get it
  89. working. I knew I was missing something obvious, but how to figure out what?&lt;/p&gt;
  90.  
  91. &lt;p&gt;Because I was dealing with nested attributes, I was assigning the selections
  92. to variables and then merging them later, so ended up with this heavily
  93. simplified (and broken) code to display a list of tiles:&lt;/p&gt;
  94.  
  95. &lt;div class=&quot;language-javascript highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  96.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt; 1&lt;/span&gt; let tiles = container.selectAll(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;.tile&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).data(data, d =&amp;gt; d.id)
  97. &lt;span class=&quot;no&quot;&gt; 2&lt;/span&gt;
  98. &lt;span class=&quot;no&quot;&gt; 3&lt;/span&gt; let tilesEnter = tiles.enter()
  99. &lt;span class=&quot;no&quot;&gt; 4&lt;/span&gt;   .append(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)
  100. &lt;span class=&quot;no&quot;&gt; 5&lt;/span&gt;     .attr(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;tiles&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
  101. &lt;span class=&quot;no&quot;&gt; 6&lt;/span&gt;
  102. &lt;span class=&quot;no&quot;&gt; 7&lt;/span&gt; tiles.select(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;.tile&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).merge(tilesEnter)
  103. &lt;span class=&quot;no&quot;&gt; 8&lt;/span&gt;   .attr(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, d =&amp;gt; d.color)
  104. &lt;span class=&quot;no&quot;&gt; 9&lt;/span&gt;
  105. &lt;span class=&quot;no&quot;&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; let contentEnter = tilesEnter
  106. &lt;span class=&quot;no&quot;&gt;11&lt;/span&gt;   .append(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)
  107. &lt;span class=&quot;no&quot;&gt;12&lt;/span&gt;     .attr(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)
  108. &lt;span class=&quot;no&quot;&gt;13&lt;/span&gt;
  109. &lt;span class=&quot;no&quot;&gt;14&lt;/span&gt; tiles.select(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;.content&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).merge(contentEnter)
  110. &lt;span class=&quot;no&quot;&gt;15&lt;/span&gt;   html(d =&amp;gt; d.content)
  111. &lt;/pre&gt;&lt;/div&gt;
  112. &lt;/div&gt;
  113. &lt;/div&gt;
  114.  
  115. &lt;p&gt;When I updated the data, the content of the tile in the child element updated,
  116. but the color at the root level did not!&lt;/p&gt;
  117.  
  118. &lt;p&gt;I tried a number of debugging approaches, but the one that I found easiest to
  119. wrap my head around, and that eventually led me to a solution, was using the
  120. &lt;a href=&quot;https://github.com/d3/d3-selection#selection_size&quot;&gt;&lt;code&gt;size()&lt;/code&gt;&lt;/a&gt; to verify how
  121. many elements where in each selection.&lt;/p&gt;
  122.  
  123. &lt;div class=&quot;language-javascript highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  124.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;1&lt;/span&gt; console.log(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;tiles entering&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, tilesEnter.size())
  125. &lt;span class=&quot;no&quot;&gt;2&lt;/span&gt; console.log(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;tiles updating&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, tiles.select(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;.tile&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).size())
  126. &lt;span class=&quot;no&quot;&gt;3&lt;/span&gt; console.log(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;content entering&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, contentEnter.size())
  127. &lt;span class=&quot;no&quot;&gt;4&lt;/span&gt; console.log(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;content updating&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, tiles.select(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;.content&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).size())
  128. &lt;/pre&gt;&lt;/div&gt;
  129. &lt;/div&gt;
  130. &lt;/div&gt;
  131.  
  132. &lt;p&gt;This allowed me to verify that for the second working case (for data with
  133. four elements) that the enter/update selections went from 4 and 0
  134. respectively to 0 and 4 when data was updated. For the first case, the update
  135. selection was always zero, and this led me to notice the extra
  136. &lt;code&gt;select('.tile')&lt;/code&gt; shouldn’t be there for the root case, since we’re already
  137. on that selection from the &lt;code&gt;selectAll&lt;/code&gt; in the initial setup!&lt;/p&gt;
  138.  
  139. &lt;p&gt;I found logging the entire selection to not be as useful, because it’s
  140. confusing what its internal state actually means.&lt;/p&gt;</content><category term="code" /><category term="javascript" /><category term="d3" /><summary type="html">Yesterday I was learning about the relatively new General Update
  141. Pattern in D3, but I couldn’t get it
  142. working. I knew I was missing something obvious, but how to figure out what?</summary></entry><entry><title type="html">Adding Last-Modified response header to Haskell Servant API</title><link href="http://localhost:4000/2018/09/30/haskell-servant-last-modified/" rel="alternate" type="text/html" title="Adding Last-Modified response header to Haskell Servant API" /><published>2018-09-30T00:00:00+00:00</published><updated>2018-09-30T00:00:00+00:00</updated><id>http://localhost:4000/2018/09/30/haskell-servant-last-modified</id><content type="html" xml:base="http://localhost:4000/2018/09/30/haskell-servant-last-modified/">&lt;p&gt;Given the following &lt;a href=&quot;https://haskell-servant.github.io/&quot;&gt;Servant API&lt;/a&gt;
  143. (boilerplate redacted for brevity):&lt;/p&gt;
  144.  
  145. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  146.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;1&lt;/span&gt; type MyAPI = &amp;quot;some-api&amp;quot; :&amp;gt; Get '[JSON] NoContent
  147. &lt;span class=&quot;no&quot;&gt;2&lt;/span&gt;
  148. &lt;span class=&quot;no&quot;&gt;3&lt;/span&gt; someApi = return NoContent
  149. &lt;/pre&gt;&lt;/div&gt;
  150. &lt;/div&gt;
  151. &lt;/div&gt;
  152.  
  153. &lt;p&gt;How do you add a &lt;code&gt;Last-Modified&lt;/code&gt; header? As a first attempt, we can use the
  154. &lt;code&gt;Header&lt;/code&gt; type with &lt;a href=&quot;http://hackage.haskell.org/package/servant-0.14.1/docs/Servant-API-ResponseHeaders.html#v:addHeader&quot;&gt;&lt;code&gt;addHeader&lt;/code&gt;&lt;/a&gt; and a &lt;code&gt;UTCTime&lt;/code&gt;:&lt;/p&gt;
  155.  
  156. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  157.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt; 1&lt;/span&gt; import Data.Time.Clock (UTCTime, getCurrentTime)
  158. &lt;span class=&quot;no&quot;&gt; 2&lt;/span&gt;
  159. &lt;span class=&quot;no&quot;&gt; 3&lt;/span&gt; type LastModifiedHeader = Header &amp;quot;Last-Modified&amp;quot; UTCTime
  160. &lt;span class=&quot;no&quot;&gt; 4&lt;/span&gt; type MyAPI = &amp;quot;some-api&amp;quot; :&amp;gt; Get '[JSON] (Headers '[LastModifiedHeader] NoContent)
  161. &lt;span class=&quot;no&quot;&gt; 5&lt;/span&gt;
  162. &lt;span class=&quot;no&quot;&gt; 6&lt;/span&gt; someApi = do
  163. &lt;span class=&quot;no&quot;&gt; 7&lt;/span&gt;   now &amp;lt;- getCurrentTime
  164. &lt;span class=&quot;no&quot;&gt; 8&lt;/span&gt;   addHeader now
  165. &lt;span class=&quot;no&quot;&gt; 9&lt;/span&gt;   return NoContent
  166. &lt;/pre&gt;&lt;/div&gt;
  167. &lt;/div&gt;
  168. &lt;/div&gt;
  169.  
  170. &lt;p&gt;Unfortunately, this returns the time in the wrong format!&lt;/p&gt;
  171.  
  172. &lt;pre&gt;&lt;code&gt;&amp;gt; curl -I localhost/some-api | grep Last-Modified
  173. Last-Modified: 2018-09-30T19:56:39Z
  174. &lt;/code&gt;&lt;/pre&gt;
  175.  
  176. &lt;p&gt;It &lt;a href=&quot;https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1&quot;&gt;should be RFC
  177. 1123&lt;/a&gt;. We can
  178. fix this with a &lt;code&gt;newtype&lt;/code&gt; that wraps the
  179. formatting functions available in &lt;code&gt;Data.Time.Format&lt;/code&gt;:&lt;/p&gt;
  180.  
  181. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  182.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt; 1&lt;/span&gt; {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  183. &lt;span class=&quot;no&quot;&gt; 2&lt;/span&gt;
  184. &lt;span class=&quot;no&quot;&gt; 3&lt;/span&gt; import Data.ByteString (pack)
  185. &lt;span class=&quot;no&quot;&gt; 4&lt;/span&gt; import Data.Time.Clock (UTCTime, getCurrentTime)
  186. &lt;span class=&quot;no&quot;&gt; 5&lt;/span&gt; import Data.Time.Format (formatTime, defaultTimeLocale, rfc1123DateFormat)
  187. &lt;span class=&quot;no&quot;&gt; 6&lt;/span&gt;
  188. &lt;span class=&quot;no&quot;&gt; 7&lt;/span&gt; newtype RFC1123Time = RFC1123Time UTCTime
  189. &lt;span class=&quot;no&quot;&gt; 8&lt;/span&gt;   deriving (Show, FormatTime)
  190. &lt;span class=&quot;no&quot;&gt; 9&lt;/span&gt;
  191. &lt;span class=&quot;no&quot;&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; instance ToHttpApiData RFC1123Time where
  192. &lt;span class=&quot;no&quot;&gt;11&lt;/span&gt;   toUrlPiece = error &amp;quot;Not intended to be used in URLs&amp;quot;
  193. &lt;span class=&quot;no&quot;&gt;12&lt;/span&gt;   toHeader =
  194. &lt;span class=&quot;no&quot;&gt;13&lt;/span&gt;     let rfc1123DateFormat = &amp;quot;%a, %_d %b %Y %H:%M:%S GMT&amp;quot; in
  195. &lt;span class=&quot;no&quot;&gt;14&lt;/span&gt;     pack . formatTime defaultTimeLocale rfc1123DateFormat
  196. &lt;span class=&quot;no&quot;&gt;15&lt;/span&gt;
  197. &lt;span class=&quot;no&quot;&gt;16&lt;/span&gt; type LastModifiedHeader = Header &amp;quot;Last-Modified&amp;quot; RFC1123Time
  198. &lt;span class=&quot;no&quot;&gt;17&lt;/span&gt; type MyAPI = &amp;quot;some-api&amp;quot; :&amp;gt; Get '[JSON] (Headers '[LastModifiedHeader] NoContent)
  199. &lt;span class=&quot;no&quot;&gt;18&lt;/span&gt;
  200. &lt;span class=&quot;no&quot;&gt;19&lt;/span&gt; someApi = do
  201. &lt;span class=&quot;no&quot;&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt;   now &amp;lt;- getCurrentTime
  202. &lt;span class=&quot;no&quot;&gt;21&lt;/span&gt;   addHeader $ RFC1123Time now
  203. &lt;span class=&quot;no&quot;&gt;22&lt;/span&gt;   return NoContent
  204. &lt;/pre&gt;&lt;/div&gt;
  205. &lt;/div&gt;
  206. &lt;/div&gt;
  207.  
  208. &lt;pre&gt;&lt;code&gt;&amp;gt; curl -I localhost/some-api | grep Last-Modified
  209. Last-Modified: Sun, 30 Sep 2018 20:44:16 GMT
  210. &lt;/code&gt;&lt;/pre&gt;
  211.  
  212. &lt;p&gt;If anyone knows a simpler way, please let me know!&lt;/p&gt;
  213.  
  214. &lt;h3 id=&quot;irreverant-technical-asides&quot;&gt;Irreverant technical asides&lt;/h3&gt;
  215.  
  216. &lt;p&gt;Many implementations reference RFC822 for &lt;code&gt;Last-Modified&lt;/code&gt; format. What gives?
  217. RFC822 was updated by RFC1123, which only adds a few clauses to tighten up the
  218. definition. Most importantly, it updates the year format from 2 digits to 4!
  219. Note that
  220. &lt;a href=&quot;http://hackage.haskell.org/package/time-1.9.2/docs/Data-Time-Format.html#v:rfc822DateFormat&quot;&gt;&lt;code&gt;Date.Time.Format.rfc882DateFormat&lt;/code&gt;&lt;/a&gt;
  221. is technically incorrect here, specifying a four digit year.
  222. &lt;a href=&quot;http://hackage.haskell.org/package/time-http-0.5/docs/Data-Time-Format-RFC822.html&quot;&gt;&lt;code&gt;Data.Time.Format.RFC822&lt;/code&gt;&lt;/a&gt;
  223. gets it right.&lt;/p&gt;
  224.  
  225. &lt;p&gt;&lt;code&gt;rfc822DateFormat&lt;/code&gt; is also technically incorrect in another way: it uses the
  226. &lt;code&gt;%Z&lt;/code&gt; format specifier for timezone, which produces &lt;code&gt;UTC&lt;/code&gt; on a &lt;code&gt;UTCTime&lt;/code&gt;. This
  227. is not an allowed value! However,
  228. &lt;a href=&quot;https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1&quot;&gt;RFC 2616&lt;/a&gt; says
  229. “for the purposes of HTTP, GMT is exactly equal to UTC” so GMT can safely be
  230. hardcoded here since we know we always have a UTC time.&lt;/p&gt;</content><category term="code" /><category term="haskell" /><category term="servant" /><summary type="html">Given the following Servant API
  231. (boilerplate redacted for brevity):</summary></entry><entry><title type="html">Using Haskell Servant to Power a Decoupled React Single Page Application</title><link href="http://localhost:4000/2018/05/10/haskell-servant-react-auth-example/" rel="alternate" type="text/html" title="Using Haskell Servant to Power a Decoupled React Single Page Application" /><published>2018-05-10T00:00:00+00:00</published><updated>2018-05-10T00:00:00+00:00</updated><id>http://localhost:4000/2018/05/10/haskell-servant-react-auth-example</id><content type="html" xml:base="http://localhost:4000/2018/05/10/haskell-servant-react-auth-example/">&lt;p&gt;Recently I’ve been experimenting with different ways of building web
  232. applications. In particular, I’m interested to what extent it is feasible to
  233. start an application with a “pure” API, as distinct from a typical Ruby on
  234. Rails application. This approach would limit the backend server to only API
  235. endpoints, and restrict it from any kind of HTML generation. All HTML concerns
  236. would be pushed to a frontend using something like React.&lt;/p&gt;
  237.  
  238. &lt;p&gt;I published an &lt;a href=&quot;https://github.com/xaviershay/haskell-servant-react-auth-example&quot;&gt;example
  239. application&lt;/a&gt;
  240. that demostrates this architecture using
  241. &lt;a href=&quot;http://haskell-servant.readthedocs.io/en/stable/&quot;&gt;Servant&lt;/a&gt; and
  242. &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;. In this post, I’ll detail some of the issues I
  243. came across getting this working.&lt;/p&gt;
  244.  
  245. &lt;h2 id=&quot;authentication&quot;&gt;Authentication&lt;/h2&gt;
  246.  
  247. &lt;p&gt;One difficultly I came across was how to handle third-party authentication (via
  248. Google OAuth) in this scenario when running the backend and frontend as
  249. completely separate services. A typical OAuth flow requires server side calls
  250. and interactions that don’t work when the flow is split over two different
  251. services.&lt;/p&gt;
  252.  
  253. &lt;p&gt;Google provides an &lt;a href=&quot;https://developers.google.com/identity/protocols/OAuth2UserAgent&quot;&gt;OAuth flow for Web
  254. Applications&lt;/a&gt;
  255. that addresses the first issue. The hard part is how to verify that
  256. authentication in the backend.&lt;/p&gt;
  257.  
  258. &lt;p&gt;This OAuth flow provides the client with a &lt;a href=&quot;https://jwt.io/&quot;&gt;JWT&lt;/a&gt; containing
  259. information about the user, such as their email and granted scopes. This can be
  260. &lt;a href=&quot;https://github.com/xaviershay/haskell-servant-react-auth-example/blob/master/api/src/Auth.hs&quot;&gt;verified and trusted on the
  261. server&lt;/a&gt;
  262. using Google’s public key, which needs to be &lt;a href=&quot;https://github.com/xaviershay/haskell-servant-react-auth-example/blob/master/api/src/KeyFetcher.hs&quot;&gt;continually fetched from their
  263. endpoint&lt;/a&gt;
  264. to keep it current.&lt;/p&gt;
  265.  
  266. &lt;p&gt;This verification can be done in Servant using a &lt;a href=&quot;http://haskell-servant.readthedocs.io/en/stable/tutorial/Authentication.html#generalized-authentication-in-action&quot;&gt;Generalized Authentication handler&lt;/a&gt;.&lt;/p&gt;
  267.  
  268. &lt;h2 id=&quot;cors&quot;&gt;CORS&lt;/h2&gt;
  269.  
  270. &lt;p&gt;Requests between applications on different hosts have to negotiate CORS
  271. correctly. This could be mitigated by running a reverse proxy in front of both
  272. services and presenting them at a single domain, but I wanted to see if I could
  273. make it work without this.&lt;/p&gt;
  274.  
  275. &lt;p&gt;A few things are required for correct &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&quot;&gt;CORS handling&lt;/a&gt;. First, appropriate &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; headers need to be set on requests. This is best handled with a &lt;a href=&quot;https://github.com/xaviershay/haskell-servant-react-auth-example/blob/master/api/app/Main.hs#L31&quot;&gt;middleware from the &lt;code&gt;wai-cors&lt;/code&gt; package&lt;/a&gt;.&lt;/p&gt;
  276.  
  277. &lt;p&gt;That would be sufficient for “simple” requests, but for since our API uses both
  278. a non-simple content type (&lt;code&gt;application/json&lt;/code&gt;) and the &lt;code&gt;Authorization&lt;/code&gt; header,
  279. they need to be added to the default policy:&lt;/p&gt;
  280.  
  281. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  282.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;1&lt;/span&gt; corsPolicy = simpleCorsResourcePolicy
  283. &lt;span class=&quot;no&quot;&gt;2&lt;/span&gt;                { corsRequestHeaders = [ &amp;quot;authorization&amp;quot;, &amp;quot;content-type&amp;quot; ]
  284. &lt;span class=&quot;no&quot;&gt;3&lt;/span&gt;                }
  285. &lt;/pre&gt;&lt;/div&gt;
  286. &lt;/div&gt;
  287. &lt;/div&gt;
  288.  
  289. &lt;p&gt;Also, these non-simple API requests will trigger a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests&quot;&gt;CORS
  290. preflight&lt;/a&gt;,
  291. which sends an &lt;code&gt;OPTIONS&lt;/code&gt; request to our API. The API needs to be extended to
  292. handle these requests.
  293. &lt;a href=&quot;https://github.com/sordina/servant-options&quot;&gt;&lt;code&gt;servant-options&lt;/code&gt;&lt;/a&gt; provides a
  294. middleware to do this automatically from an API definition. Unfortunately, &lt;code&gt;servant-options&lt;/code&gt; didn’t work &lt;a href=&quot;https://github.com/sordina/servant-options/issues/2&quot;&gt;out of the box&lt;/a&gt; with &lt;code&gt;servant-auth&lt;/code&gt;. I needed to provide an instance of &lt;code&gt;HasForeign&lt;/code&gt; for &lt;code&gt;AuthProtect&lt;/code&gt;. A simple pass-through implementation looks like this:&lt;/p&gt;
  295.  
  296. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  297.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;1&lt;/span&gt; instance (HasForeign lang ftype api) =&amp;gt;
  298. &lt;span class=&quot;no&quot;&gt;2&lt;/span&gt;   HasForeign lang ftype (AuthProtect k :&amp;gt; api) where
  299. &lt;span class=&quot;no&quot;&gt;3&lt;/span&gt;
  300. &lt;span class=&quot;no&quot;&gt;4&lt;/span&gt;   type Foreign ftype (AuthProtect k :&amp;gt; api) = Foreign ftype api
  301. &lt;span class=&quot;no&quot;&gt;5&lt;/span&gt;
  302. &lt;span class=&quot;no&quot;&gt;6&lt;/span&gt;   foreignFor lang Proxy Proxy subR =
  303. &lt;span class=&quot;no&quot;&gt;7&lt;/span&gt;     foreignFor lang Proxy (Proxy :: Proxy api) subR
  304. &lt;/pre&gt;&lt;/div&gt;
  305. &lt;/div&gt;
  306. &lt;/div&gt;
  307.  
  308. &lt;p&gt;I later &lt;a href=&quot;https://github.com/xaviershay/haskell-servant-react-auth-example/blob/master/api/src/Api.hs#L29&quot;&gt;extended
  309. this&lt;/a&gt;
  310. to include appropriate metadata so that I could use it to generate clients
  311. correctly.&lt;/p&gt;
  312.  
  313. &lt;h2 id=&quot;js-clients&quot;&gt;JS Clients&lt;/h2&gt;
  314.  
  315. &lt;p&gt;A nice thing about Servant is the ability to auto-generate client wrappers for
  316. your API. &lt;code&gt;servant-js&lt;/code&gt; provides a number of formats for this, though they
  317. weren’t as ergonomic as I was hoping. It doesn’t currently have &lt;a href=&quot;https://github.com/haskell-servant/servant-auth/issues/8&quot;&gt;support for
  318. &lt;code&gt;servant-auth&lt;/code&gt;&lt;/a&gt; nor
  319. support for ES6-style &lt;code&gt;exports&lt;/code&gt;. Rather than solve this generically, I wrote a
  320. &lt;a href=&quot;https://github.com/xaviershay/haskell-servant-react-auth-example/blob/master/api/src/JsGeneration.hs&quot;&gt;custom
  321. generator&lt;/a&gt;.
  322. For fun, it outputs an API class that allows an authorization token to be
  323. supplied in the constructor, rather than as an argument to every function:&lt;/p&gt;
  324.  
  325. &lt;div class=&quot;language-javascript highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  326.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;1&lt;/span&gt; let api = &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;new&lt;/span&gt; Api(jwt);
  327. &lt;span class=&quot;no&quot;&gt;2&lt;/span&gt; api.getEmail();
  328. &lt;/pre&gt;&lt;/div&gt;
  329. &lt;/div&gt;
  330. &lt;/div&gt;
  331.  
  332. &lt;p&gt;I’m not sure what the best way to distribute this API is. Currently, the
  333. example writes out a file in the frontend’s source tree. This works great for
  334. development, but for production I would consider either a dedicated build step
  335. in packaging, or serving the JS up directly from the API server.&lt;/p&gt;
  336.  
  337. &lt;p&gt;Aside from this generated client, I didn’t do anything particularly interesting
  338. on the React front. The app included in the example is very simple.&lt;/p&gt;
  339.  
  340. &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
  341.  
  342. &lt;p&gt;This wasn’t a big enough project to draw any serious conclusions about the
  343. approach. It is evident however that Servant still has a couple of rough edges
  344. when you get outside of the common cases. It took a while to wrap my head around how Servant uses the type system. I found &lt;a href=&quot;https://www.well-typed.com/blog/2015/11/implementing-a-minimal-version-of-haskell-servant/&quot;&gt;this post and exercise&lt;/a&gt; very helpful.&lt;/p&gt;
  345.  
  346. &lt;p&gt;I hadn’t used JWTs before, and they strike me as a pretty neat way to thread authentication through a distributed application.&lt;/p&gt;</content><category term="code" /><category term="haskell" /><category term="servant" /><summary type="html">Recently I’ve been experimenting with different ways of building web
  347. applications. In particular, I’m interested to what extent it is feasible to
  348. start an application with a “pure” API, as distinct from a typical Ruby on
  349. Rails application. This approach would limit the backend server to only API
  350. endpoints, and restrict it from any kind of HTML generation. All HTML concerns
  351. would be pushed to a frontend using something like React.</summary></entry><entry><title type="html">2017 Contributions</title><link href="http://localhost:4000/2017/12/31/2017-contributions/" rel="alternate" type="text/html" title="2017 Contributions" /><published>2017-12-31T00:00:00+00:00</published><updated>2017-12-31T00:00:00+00:00</updated><id>http://localhost:4000/2017/12/31/2017-contributions</id><content type="html" xml:base="http://localhost:4000/2017/12/31/2017-contributions/">&lt;p&gt;This was a light year for open source contribution, 168 by Github’s count (and
  352. some uncounted on Bitbucket). I’ve continued on the RSpec core team, though the
  353. project is mostly stable and I haven’t been particularly active. I did find
  354. time to experiment with some new things however:&lt;/p&gt;
  355.  
  356. &lt;ul&gt;
  357.  &lt;li&gt;Windows development! A &lt;a href=&quot;https://bitbucket.org/Nicksaurus/foreman/pull-requests/17&quot;&gt;rather major PR&lt;/a&gt; to Foreman to switch out the core solver and fix some UI lockups (among others) was the first time I’ve written C# in a decade. It, and the relevant UI libraries, are quite nice. Unfortunately the maintainer hasn’t had time for the project so it’s basically stalled. A fork is probably due. I also made a trivial patch to the &lt;a href=&quot;https://bitbucket.org/Nicksaurus/foreman/pull-requests/17&quot;&gt;Ori Livesplitter&lt;/a&gt;.&lt;/li&gt;
  358.  &lt;li&gt;Small forays into frontend development with a &lt;a href=&quot;https://github.com/xaviershay/kssu-timer&quot;&gt;KSSU timer&lt;/a&gt; and a &lt;a href=&quot;https://github.com/xaviershay/runnersonly&quot;&gt;glorious troll site&lt;/a&gt; both in React, and some &lt;a href=&quot;https://github.com/yupferris/assistant/pull/3&quot;&gt;assistant&lt;/a&gt; &lt;a href=&quot;https://github.com/yupferris/assistant/pull/4&quot;&gt;contributions&lt;/a&gt; with VueJS.&lt;/li&gt;
  359.  &lt;li&gt;Taking advantage of my new Pixel phone to try my hand at Android development, with &lt;a href=&quot;https://github.com/aricneto/TwistyTimer/pull/113&quot;&gt;contributions to Twisty Timer&lt;/a&gt; and a new &lt;a href=&quot;https://github.com/yupferris/assistant/pull/4&quot;&gt;system keyboard for input of Rubix cube algorithms&lt;/a&gt;.&lt;/li&gt;
  360.  &lt;li&gt;Continued leveling up in Haskell with a &lt;a href=&quot;https://github.com/xaviershay/factorio-hs&quot;&gt;Factorio data parser&lt;/a&gt; (likely broken on recent versions) and a woefully incomplete &lt;a href=&quot;https://github.com/xaviershay/mopus-gagnum&quot;&gt;clone of Opus Magnum&lt;/a&gt;. I’m feeling reasonably confident with it now, and it’s currently my go-to language for new projects.&lt;/li&gt;
  361. &lt;/ul&gt;
  362.  
  363. &lt;p&gt;And as always, a &lt;a href=&quot;https://github.com/looker/looker-sdk-ruby/issues/55&quot;&gt;smattering&lt;/a&gt; &lt;a href=&quot;https://github.com/stripe-contrib/pagerbot/issues/46&quot;&gt;of&lt;/a&gt; &lt;a href=&quot;https://github.com/seattlerb/minitest/pull/672&quot;&gt;issues&lt;/a&gt; to help improve documentation. Leave things better than you found them!&lt;/p&gt;
  364.  
  365. &lt;p&gt;Next year, I’m looking forward to playing around with &lt;a href=&quot;https://firebase.google.com/&quot;&gt;Firebase&lt;/a&gt;, and checking back in on &lt;a href=&quot;https://www.rust-lang.org/en-US/&quot;&gt;Rust&lt;/a&gt; to see how it’s progressing.&lt;/p&gt;</content><category term="code" /><summary type="html">This was a light year for open source contribution, 168 by Github’s count (and
  366. some uncounted on Bitbucket). I’ve continued on the RSpec core team, though the
  367. project is mostly stable and I haven’t been particularly active. I did find
  368. time to experiment with some new things however:</summary></entry><entry><title type="html">Migrating Enki to Jekyll</title><link href="http://localhost:4000/2017/01/01/migrating-enki-to-jekyll/" rel="alternate" type="text/html" title="Migrating Enki to Jekyll" /><published>2017-01-01T00:00:00+00:00</published><updated>2017-01-01T00:00:00+00:00</updated><id>http://localhost:4000/2017/01/01/migrating-enki-to-jekyll</id><content type="html" xml:base="http://localhost:4000/2017/01/01/migrating-enki-to-jekyll/">&lt;p&gt;I just converted this blog from a dynamic &lt;a href=&quot;https://github.com/xaviershay/enki&quot;&gt;Enki&lt;/a&gt; site to a static &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; one. I wanted to get rid of the comments, add &lt;span class=&quot;caps&quot;&gt;SSL&lt;/span&gt;, and not have to upgrade Rails so often. I prefer composing locally also.&lt;/p&gt;
  369. &lt;p&gt;First, I exported all of the posts to lesstile templates using a rake task.&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  370.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  371. &lt;/tt&gt;2&lt;tt&gt;
  372. &lt;/tt&gt;3&lt;tt&gt;
  373. &lt;/tt&gt;4&lt;tt&gt;
  374. &lt;/tt&gt;5&lt;tt&gt;
  375. &lt;/tt&gt;6&lt;tt&gt;
  376. &lt;/tt&gt;7&lt;tt&gt;
  377. &lt;/tt&gt;8&lt;tt&gt;
  378. &lt;/tt&gt;9&lt;tt&gt;
  379. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  380. &lt;/tt&gt;11&lt;tt&gt;
  381. &lt;/tt&gt;12&lt;tt&gt;
  382. &lt;/tt&gt;13&lt;tt&gt;
  383. &lt;/tt&gt;14&lt;tt&gt;
  384. &lt;/tt&gt;15&lt;tt&gt;
  385. &lt;/tt&gt;16&lt;tt&gt;
  386. &lt;/tt&gt;17&lt;tt&gt;
  387. &lt;/tt&gt;18&lt;tt&gt;
  388. &lt;/tt&gt;19&lt;tt&gt;
  389. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  390. &lt;/tt&gt;21&lt;tt&gt;
  391. &lt;/tt&gt;22&lt;tt&gt;
  392. &lt;/tt&gt;23&lt;tt&gt;
  393. &lt;/tt&gt;24&lt;tt&gt;
  394. &lt;/tt&gt;25&lt;tt&gt;
  395. &lt;/tt&gt;26&lt;tt&gt;
  396. &lt;/tt&gt;27&lt;tt&gt;
  397. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  398.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;task &lt;span style=&quot;color:#A60&quot;&gt;:export_posts&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color:#A60&quot;&gt;:environment&lt;/span&gt; &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
  399. &lt;/tt&gt;  &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;Post&lt;/span&gt;.find_each &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;do&lt;/span&gt; |post|&lt;tt&gt;
  400. &lt;/tt&gt;    filename = &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;%s-%s.lesstile&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; % [&lt;tt&gt;
  401. &lt;/tt&gt;      post.published_at.strftime(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;%Y-%m-%d&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;),&lt;tt&gt;
  402. &lt;/tt&gt;      post.slug&lt;tt&gt;
  403. &lt;/tt&gt;    ]&lt;tt&gt;
  404. &lt;/tt&gt;&lt;tt&gt;
  405. &lt;/tt&gt;    dir = &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;_posts&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  406. &lt;/tt&gt;    yaml_sep = &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;---&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  407. &lt;/tt&gt;&lt;tt&gt;
  408. &lt;/tt&gt;    puts filename&lt;tt&gt;
  409. &lt;/tt&gt;&lt;tt&gt;
  410. &lt;/tt&gt;    body = &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;lt;&amp;lt;-EOS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;tt&gt;
  411. &lt;/tt&gt;&lt;span style=&quot;background:#ddd;color:black&quot;&gt;&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;#{&lt;/span&gt;yaml_sep&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;&lt;tt&gt;
  412. &lt;/tt&gt;layout: post&lt;tt&gt;
  413. &lt;/tt&gt;title:  &lt;/span&gt;&lt;span style=&quot;background:#ddd;color:black&quot;&gt;&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;#{&lt;/span&gt;post.title.inspect&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;&lt;tt&gt;
  414. &lt;/tt&gt;date:   &lt;/span&gt;&lt;span style=&quot;background:#ddd;color:black&quot;&gt;&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;#{&lt;/span&gt;post.published_at.strftime(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;%F %T %:z&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;&lt;tt&gt;
  415. &lt;/tt&gt;tags:   &lt;/span&gt;&lt;span style=&quot;background:#ddd;color:black&quot;&gt;&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;#{&lt;/span&gt;post.tags.map {|x| x.name.downcase }.sort.inspect&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  416. &lt;/tt&gt;&lt;span style=&quot;background:#ddd;color:black&quot;&gt;&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;#{&lt;/span&gt;yaml_sep&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;&lt;tt&gt;
  417. &lt;/tt&gt;{% raw %}&lt;tt&gt;
  418. &lt;/tt&gt;&lt;/span&gt;&lt;span style=&quot;background:#ddd;color:black&quot;&gt;&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;#{&lt;/span&gt;post.body&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;&lt;tt&gt;
  419. &lt;/tt&gt;{% endraw %}&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&lt;tt&gt;
  420. &lt;/tt&gt;    EOS&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  421. &lt;/tt&gt;&lt;tt&gt;
  422. &lt;/tt&gt;    &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;File&lt;/span&gt;.write(&lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;File&lt;/span&gt;.join(dir, filename), body)&lt;tt&gt;
  423. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  424. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  425. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  426. &lt;/tr&gt;&lt;/table&gt;
  427. &lt;p&gt;&lt;a href=&quot;https://github.com/xaviershay/lesstile&quot;&gt;Lesstile&lt;/a&gt; is a wrapper around Textile that provides some extra functionality, so a custom converter is also needed. Put the following in &lt;code&gt;_plugins/lesstile.rb&lt;/code&gt; (with associated additions to your &lt;code&gt;Gemfile&lt;/code&gt;):&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  428.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  429. &lt;/tt&gt;2&lt;tt&gt;
  430. &lt;/tt&gt;3&lt;tt&gt;
  431. &lt;/tt&gt;4&lt;tt&gt;
  432. &lt;/tt&gt;5&lt;tt&gt;
  433. &lt;/tt&gt;6&lt;tt&gt;
  434. &lt;/tt&gt;7&lt;tt&gt;
  435. &lt;/tt&gt;8&lt;tt&gt;
  436. &lt;/tt&gt;9&lt;tt&gt;
  437. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  438. &lt;/tt&gt;11&lt;tt&gt;
  439. &lt;/tt&gt;12&lt;tt&gt;
  440. &lt;/tt&gt;13&lt;tt&gt;
  441. &lt;/tt&gt;14&lt;tt&gt;
  442. &lt;/tt&gt;15&lt;tt&gt;
  443. &lt;/tt&gt;16&lt;tt&gt;
  444. &lt;/tt&gt;17&lt;tt&gt;
  445. &lt;/tt&gt;18&lt;tt&gt;
  446. &lt;/tt&gt;19&lt;tt&gt;
  447. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  448. &lt;/tt&gt;21&lt;tt&gt;
  449. &lt;/tt&gt;22&lt;tt&gt;
  450. &lt;/tt&gt;23&lt;tt&gt;
  451. &lt;/tt&gt;24&lt;tt&gt;
  452. &lt;/tt&gt;25&lt;tt&gt;
  453. &lt;/tt&gt;26&lt;tt&gt;
  454. &lt;/tt&gt;27&lt;tt&gt;
  455. &lt;/tt&gt;28&lt;tt&gt;
  456. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  457.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;require &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;lesstile&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  458. &lt;/tt&gt;require &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;coderay&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  459. &lt;/tt&gt;require &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;RedCloth&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  460. &lt;/tt&gt;&lt;tt&gt;
  461. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color:#B06;font-weight:bold&quot;&gt;Jekyll&lt;/span&gt;&lt;tt&gt;
  462. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color:#B06;font-weight:bold&quot;&gt;LesstileConverter&lt;/span&gt; &amp;lt; &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;Converter&lt;/span&gt;&lt;tt&gt;
  463. &lt;/tt&gt;    safe &lt;span style=&quot;color:#038;font-weight:bold&quot;&gt;true&lt;/span&gt;&lt;tt&gt;
  464. &lt;/tt&gt;    priority &lt;span style=&quot;color:#A60&quot;&gt;:low&lt;/span&gt;&lt;tt&gt;
  465. &lt;/tt&gt;&lt;tt&gt;
  466. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;matches&lt;/span&gt;(ext)&lt;tt&gt;
  467. &lt;/tt&gt;      ext =~ &lt;span style=&quot;background-color:#fff0ff&quot;&gt;&lt;span style=&quot;color:#404&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#808&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:#04D&quot;&gt;\.&lt;/span&gt;&lt;span style=&quot;color:#808&quot;&gt;lesstile$&lt;/span&gt;&lt;span style=&quot;color:#404&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#C2C&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  468. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  469. &lt;/tt&gt;&lt;tt&gt;
  470. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;output_ext&lt;/span&gt;(ext)&lt;tt&gt;
  471. &lt;/tt&gt;      &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;.html&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  472. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  473. &lt;/tt&gt;&lt;tt&gt;
  474. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;convert&lt;/span&gt;(content)&lt;tt&gt;
  475. &lt;/tt&gt;      &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;Lesstile&lt;/span&gt;.format_as_xhtml(&lt;tt&gt;
  476. &lt;/tt&gt;        content,&lt;tt&gt;
  477. &lt;/tt&gt;        &lt;span style=&quot;color:#A60&quot;&gt;:text_formatter&lt;/span&gt; =&amp;gt; lambda {|text|&lt;tt&gt;
  478. &lt;/tt&gt;          &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;RedCloth&lt;/span&gt;.new(&lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;CGI&lt;/span&gt;::unescapeHTML(text)).to_html&lt;tt&gt;
  479. &lt;/tt&gt;        },&lt;tt&gt;
  480. &lt;/tt&gt;        &lt;span style=&quot;color:#A60&quot;&gt;:code_formatter&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;Lesstile&lt;/span&gt;::&lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;CodeRayFormatter&lt;/span&gt;&lt;tt&gt;
  481. &lt;/tt&gt;      )&lt;tt&gt;
  482. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  483. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  484. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  485. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  486. &lt;/tr&gt;&lt;/table&gt;
  487. &lt;p&gt;The &lt;code&gt;permalink&lt;/code&gt; configuration option needs to be set to match existing URLs, and to create the tag pages, use the &lt;code&gt;jekyll-archives&lt;/code&gt; plugin.&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  488.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  489. &lt;/tt&gt;2&lt;tt&gt;
  490. &lt;/tt&gt;3&lt;tt&gt;
  491. &lt;/tt&gt;4&lt;tt&gt;
  492. &lt;/tt&gt;5&lt;tt&gt;
  493. &lt;/tt&gt;6&lt;tt&gt;
  494. &lt;/tt&gt;7&lt;tt&gt;
  495. &lt;/tt&gt;8&lt;tt&gt;
  496. &lt;/tt&gt;9&lt;tt&gt;
  497. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  498. &lt;/tt&gt;11&lt;tt&gt;
  499. &lt;/tt&gt;12&lt;tt&gt;
  500. &lt;/tt&gt;13&lt;tt&gt;
  501. &lt;/tt&gt;14&lt;tt&gt;
  502. &lt;/tt&gt;15&lt;tt&gt;
  503. &lt;/tt&gt;16&lt;tt&gt;
  504. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  505.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;&lt;span style=&quot;color:#808&quot;&gt;permalink&lt;/span&gt;: &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;/:year/:month/:day/:title/&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  506. &lt;/tt&gt;&lt;tt&gt;
  507. &lt;/tt&gt;&lt;span style=&quot;color:#808&quot;&gt;assets&lt;/span&gt;:&lt;tt&gt;
  508. &lt;/tt&gt;  &lt;span style=&quot;color:#808&quot;&gt;digest&lt;/span&gt;: &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;true&lt;/span&gt;&lt;tt&gt;
  509. &lt;/tt&gt;&lt;tt&gt;
  510. &lt;/tt&gt;&lt;span style=&quot;color:#808&quot;&gt;&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;jekyll-archives&lt;span style=&quot;color:#606&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;tt&gt;
  511. &lt;/tt&gt;  &lt;span style=&quot;color:#808&quot;&gt;enabled&lt;/span&gt;:&lt;tt&gt;
  512. &lt;/tt&gt;    - &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;tags&lt;/span&gt;&lt;tt&gt;
  513. &lt;/tt&gt;  &lt;span style=&quot;color:#808&quot;&gt;layout&lt;/span&gt;: &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;'tag'&lt;/span&gt;&lt;tt&gt;
  514. &lt;/tt&gt;  &lt;span style=&quot;color:#808&quot;&gt;permalinks&lt;/span&gt;:&lt;tt&gt;
  515. &lt;/tt&gt;    &lt;span style=&quot;color:#808&quot;&gt;tag&lt;/span&gt;: &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;'/:name/'&lt;/span&gt;&lt;tt&gt;
  516. &lt;/tt&gt;&lt;tt&gt;
  517. &lt;/tt&gt;&lt;span style=&quot;color:#808&quot;&gt;gems&lt;/span&gt;:&lt;tt&gt;
  518. &lt;/tt&gt;  - &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;jekyll-feed&lt;/span&gt;&lt;tt&gt;
  519. &lt;/tt&gt;  - &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;jekyll-assets&lt;/span&gt;&lt;tt&gt;
  520. &lt;/tt&gt;  - &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;jekyll-archives&lt;/span&gt;&lt;tt&gt;
  521. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  522. &lt;/tr&gt;&lt;/table&gt;
  523. &lt;p&gt;For the archives page, use an empty &lt;code&gt;archives.md&lt;/code&gt; in the root directory with a custom layout:&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  524.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  525. &lt;/tt&gt;2&lt;tt&gt;
  526. &lt;/tt&gt;3&lt;tt&gt;
  527. &lt;/tt&gt;4&lt;tt&gt;
  528. &lt;/tt&gt;5&lt;tt&gt;
  529. &lt;/tt&gt;6&lt;tt&gt;
  530. &lt;/tt&gt;7&lt;tt&gt;
  531. &lt;/tt&gt;8&lt;tt&gt;
  532. &lt;/tt&gt;9&lt;tt&gt;
  533. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  534. &lt;/tt&gt;11&lt;tt&gt;
  535. &lt;/tt&gt;12&lt;tt&gt;
  536. &lt;/tt&gt;13&lt;tt&gt;
  537. &lt;/tt&gt;14&lt;tt&gt;
  538. &lt;/tt&gt;15&lt;tt&gt;
  539. &lt;/tt&gt;16&lt;tt&gt;
  540. &lt;/tt&gt;17&lt;tt&gt;
  541. &lt;/tt&gt;18&lt;tt&gt;
  542. &lt;/tt&gt;19&lt;tt&gt;
  543. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  544. &lt;/tt&gt;21&lt;tt&gt;
  545. &lt;/tt&gt;22&lt;tt&gt;
  546. &lt;/tt&gt;23&lt;tt&gt;
  547. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  548.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;{% include head.html %}&lt;tt&gt;
  549. &lt;/tt&gt;{% assign last_month = nil %}&lt;tt&gt;
  550. &lt;/tt&gt;&amp;lt;ul&amp;gt;&lt;tt&gt;
  551. &lt;/tt&gt;{% for post in site.posts %}&lt;tt&gt;
  552. &lt;/tt&gt;  {% assign current_month = post.date | date: '%B %Y' %}&lt;tt&gt;
  553. &lt;/tt&gt;  {% if current_month != last_month %}&lt;tt&gt;
  554. &lt;/tt&gt;    &amp;lt;/ul&amp;gt;&lt;tt&gt;
  555. &lt;/tt&gt;    &amp;lt;h3&amp;gt;{{ current_month }}&amp;lt;/h3&amp;gt;&lt;tt&gt;
  556. &lt;/tt&gt;    &amp;lt;ul&amp;gt;&lt;tt&gt;
  557. &lt;/tt&gt;  {% endif %}&lt;tt&gt;
  558. &lt;/tt&gt;&lt;tt&gt;
  559. &lt;/tt&gt;  &amp;lt;li&amp;gt;&lt;tt&gt;
  560. &lt;/tt&gt;    &amp;lt;a href=&amp;quot;{{ post.url }}&amp;quot;&amp;gt;{{ post.title }}&amp;lt;/a&amp;gt;&lt;tt&gt;
  561. &lt;/tt&gt;&lt;tt&gt;
  562. &lt;/tt&gt;    {% if post.tags != empty %}&lt;tt&gt;
  563. &lt;/tt&gt;    ({% for tag in post.tags %}&amp;lt;a href='/{{ tag }}'&amp;gt;{{ tag }}&amp;lt;/a&amp;gt;{% if forloop.last %}{% else %}, {% endif %}{% endfor %})&lt;tt&gt;
  564. &lt;/tt&gt;    {% endif %}&lt;tt&gt;
  565. &lt;/tt&gt;  &amp;lt;/li&amp;gt;&lt;tt&gt;
  566. &lt;/tt&gt;&lt;tt&gt;
  567. &lt;/tt&gt;  {% assign last_month = current_month %}&lt;tt&gt;
  568. &lt;/tt&gt;{% endfor %}&lt;tt&gt;
  569. &lt;/tt&gt;&amp;lt;/ul&amp;gt;&lt;tt&gt;
  570. &lt;/tt&gt;{% include footer.html %}&lt;tt&gt;
  571. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  572. &lt;/tr&gt;&lt;/table&gt;
  573. &lt;p&gt;For a full example, including a recommended set of layouts and includes, see the &lt;a href=&quot;https://github.com/xaviershay/rhnh-static&quot;&gt;new sources&lt;/a&gt; for this site.&lt;/p&gt;</content><category term="code" /><category term="enki" /><category term="jekyll" /><summary type="html">I just converted this blog from a dynamic Enki site to a static Jekyll one. I wanted to get rid of the comments, add SSL, and not have to upgrade Rails so often. I prefer composing locally also.</summary></entry><entry><title type="html">New non-tech blog</title><link href="http://localhost:4000/2014/10/12/new-non-tech-blog/" rel="alternate" type="text/html" title="New non-tech blog" /><published>2014-10-12T22:30:00+00:00</published><updated>2014-10-12T22:30:00+00:00</updated><id>http://localhost:4000/2014/10/12/new-non-tech-blog</id><content type="html" xml:base="http://localhost:4000/2014/10/12/new-non-tech-blog/">&lt;p&gt;Have been writing a bit recently, just not here. More politics and book reviews. I&amp;#8217;ve separated it out over on &lt;a href=&quot;https://xaviershay.github.io/blog/&quot;&gt;Github pages&lt;/a&gt;.&lt;/p&gt;</content><summary type="html">Have been writing a bit recently, just not here. More politics and book reviews. I&amp;#8217;ve separated it out over on Github pages.</summary></entry><entry><title type="html">Dropwizard logger for Ruby and WEBrick</title><link href="http://localhost:4000/2014/08/17/dropwizard-logger-for-ruby-and-webrick/" rel="alternate" type="text/html" title="Dropwizard logger for Ruby and WEBrick" /><published>2014-08-17T22:30:19+00:00</published><updated>2014-08-17T22:30:19+00:00</updated><id>http://localhost:4000/2014/08/17/dropwizard-logger-for-ruby-and-webrick</id><content type="html" xml:base="http://localhost:4000/2014/08/17/dropwizard-logger-for-ruby-and-webrick/">&lt;p&gt;Wouldn&amp;#8217;t it be great if instead of webrick logs looking like:&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  574.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  575. &lt;/tt&gt;2&lt;tt&gt;
  576. &lt;/tt&gt;3&lt;tt&gt;
  577. &lt;/tt&gt;4&lt;tt&gt;
  578. &lt;/tt&gt;5&lt;tt&gt;
  579. &lt;/tt&gt;6&lt;tt&gt;
  580. &lt;/tt&gt;7&lt;tt&gt;
  581. &lt;/tt&gt;8&lt;tt&gt;
  582. &lt;/tt&gt;9&lt;tt&gt;
  583. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  584. &lt;/tt&gt;11&lt;tt&gt;
  585. &lt;/tt&gt;12&lt;tt&gt;
  586. &lt;/tt&gt;13&lt;tt&gt;
  587. &lt;/tt&gt;14&lt;tt&gt;
  588. &lt;/tt&gt;15&lt;tt&gt;
  589. &lt;/tt&gt;16&lt;tt&gt;
  590. &lt;/tt&gt;17&lt;tt&gt;
  591. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  592.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;&amp;gt; ruby server.rb&lt;tt&gt;
  593. &lt;/tt&gt;[2014-08-17 15:29:10] INFO  WEBrick 1.3.1&lt;tt&gt;
  594. &lt;/tt&gt;[2014-08-17 15:29:10] INFO  ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0]&lt;tt&gt;
  595. &lt;/tt&gt;[2014-08-17 15:29:10] INFO  WEBrick::HTTPServer#start: pid=17304 port=8000&lt;tt&gt;
  596. &lt;/tt&gt;D, [2014-08-17T15:29:11.452223 #17304] DEBUG -- : hello from in the request&lt;tt&gt;
  597. &lt;/tt&gt;localhost - - [17/Aug/2014:15:29:11 PDT] &amp;quot;GET / HTTP/1.1&amp;quot; 200 13&lt;tt&gt;
  598. &lt;/tt&gt;- -&amp;gt; /&lt;tt&gt;
  599. &lt;/tt&gt;E, [2014-08-17T15:29:12.787505 #17304] ERROR -- : fail (RuntimeError)&lt;tt&gt;
  600. &lt;/tt&gt;server.rb:57:in `block in &amp;lt;main&amp;gt;'&lt;tt&gt;
  601. &lt;/tt&gt;/Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `call'&lt;tt&gt;
  602. &lt;/tt&gt;/Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `do_GET'&lt;tt&gt;
  603. &lt;/tt&gt;/Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/abstract.rb:106:in `service'&lt;tt&gt;
  604. &lt;/tt&gt;/Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service'&lt;tt&gt;
  605. &lt;/tt&gt;/Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run'&lt;tt&gt;
  606. &lt;/tt&gt;/Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/server.rb:295:in `block in start_thread'&lt;tt&gt;
  607. &lt;/tt&gt;localhost - - [17/Aug/2014:15:29:12 PDT] &amp;quot;GET /fail HTTP/1.1&amp;quot; 500 6&lt;tt&gt;
  608. &lt;/tt&gt;- -&amp;gt; /fail&lt;tt&gt;
  609. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  610. &lt;/tr&gt;&lt;/table&gt;
  611. &lt;p&gt;They looked like:&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  612.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  613. &lt;/tt&gt;2&lt;tt&gt;
  614. &lt;/tt&gt;3&lt;tt&gt;
  615. &lt;/tt&gt;4&lt;tt&gt;
  616. &lt;/tt&gt;5&lt;tt&gt;
  617. &lt;/tt&gt;6&lt;tt&gt;
  618. &lt;/tt&gt;7&lt;tt&gt;
  619. &lt;/tt&gt;8&lt;tt&gt;
  620. &lt;/tt&gt;9&lt;tt&gt;
  621. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  622. &lt;/tt&gt;11&lt;tt&gt;
  623. &lt;/tt&gt;12&lt;tt&gt;
  624. &lt;/tt&gt;13&lt;tt&gt;
  625. &lt;/tt&gt;14&lt;tt&gt;
  626. &lt;/tt&gt;15&lt;tt&gt;
  627. &lt;/tt&gt;16&lt;tt&gt;
  628. &lt;/tt&gt;17&lt;tt&gt;
  629. &lt;/tt&gt;18&lt;tt&gt;
  630. &lt;/tt&gt;19&lt;tt&gt;
  631. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  632. &lt;/tt&gt;21&lt;tt&gt;
  633. &lt;/tt&gt;22&lt;tt&gt;
  634. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  635.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;&amp;gt; ruby server.rb&lt;tt&gt;
  636. &lt;/tt&gt;&lt;tt&gt;
  637. &lt;/tt&gt;   ,~~.,''&amp;quot;'`'.~~.&lt;tt&gt;
  638. &lt;/tt&gt;  : {` .- _ -. '} ;&lt;tt&gt;
  639. &lt;/tt&gt;   `:   O(_)O   ;'&lt;tt&gt;
  640. &lt;/tt&gt;    ';  ._|_,  ;`   i am starting the server&lt;tt&gt;
  641. &lt;/tt&gt;     '`-.\_/,.'`&lt;tt&gt;
  642. &lt;/tt&gt;&lt;tt&gt;
  643. &lt;/tt&gt;INFO  [2014-08-17 22:28:13,186] webrick: WEBrick 1.3.1&lt;tt&gt;
  644. &lt;/tt&gt;INFO  [2014-08-17 22:28:13,186] webrick: ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0]&lt;tt&gt;
  645. &lt;/tt&gt;INFO  [2014-08-17 22:28:13,187] webrick: WEBrick::HTTPServer#start: pid=17253 port=8000&lt;tt&gt;
  646. &lt;/tt&gt;DEBUG [2014-08-17 22:28:14,738] app: hello from in the request&lt;tt&gt;
  647. &lt;/tt&gt;INFO  [2014-08-17 15:28:14,736] webrick: GET / 200&lt;tt&gt;
  648. &lt;/tt&gt;ERROR [2014-08-17 22:28:15,603] app: RuntimeError: fail&lt;tt&gt;
  649. &lt;/tt&gt;! server.rb:57:in `block in &amp;lt;main&amp;gt;'&lt;tt&gt;
  650. &lt;/tt&gt;! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `call'&lt;tt&gt;
  651. &lt;/tt&gt;! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `do_GET'&lt;tt&gt;
  652. &lt;/tt&gt;! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/abstract.rb:106:in `service'&lt;tt&gt;
  653. &lt;/tt&gt;! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service'&lt;tt&gt;
  654. &lt;/tt&gt;! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run'&lt;tt&gt;
  655. &lt;/tt&gt;! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/server.rb:295:in `block in start_thread'&lt;tt&gt;
  656. &lt;/tt&gt;INFO  [2014-08-17 15:28:15,602] webrick: GET /fail 500&lt;tt&gt;
  657. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  658. &lt;/tr&gt;&lt;/table&gt;
  659. &lt;p&gt;I thought so, hence:&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  660.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  661. &lt;/tt&gt;2&lt;tt&gt;
  662. &lt;/tt&gt;3&lt;tt&gt;
  663. &lt;/tt&gt;4&lt;tt&gt;
  664. &lt;/tt&gt;5&lt;tt&gt;
  665. &lt;/tt&gt;6&lt;tt&gt;
  666. &lt;/tt&gt;7&lt;tt&gt;
  667. &lt;/tt&gt;8&lt;tt&gt;
  668. &lt;/tt&gt;9&lt;tt&gt;
  669. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  670. &lt;/tt&gt;11&lt;tt&gt;
  671. &lt;/tt&gt;12&lt;tt&gt;
  672. &lt;/tt&gt;13&lt;tt&gt;
  673. &lt;/tt&gt;14&lt;tt&gt;
  674. &lt;/tt&gt;15&lt;tt&gt;
  675. &lt;/tt&gt;16&lt;tt&gt;
  676. &lt;/tt&gt;17&lt;tt&gt;
  677. &lt;/tt&gt;18&lt;tt&gt;
  678. &lt;/tt&gt;19&lt;tt&gt;
  679. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  680. &lt;/tt&gt;21&lt;tt&gt;
  681. &lt;/tt&gt;22&lt;tt&gt;
  682. &lt;/tt&gt;23&lt;tt&gt;
  683. &lt;/tt&gt;24&lt;tt&gt;
  684. &lt;/tt&gt;25&lt;tt&gt;
  685. &lt;/tt&gt;26&lt;tt&gt;
  686. &lt;/tt&gt;27&lt;tt&gt;
  687. &lt;/tt&gt;28&lt;tt&gt;
  688. &lt;/tt&gt;29&lt;tt&gt;
  689. &lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
  690. &lt;/tt&gt;31&lt;tt&gt;
  691. &lt;/tt&gt;32&lt;tt&gt;
  692. &lt;/tt&gt;33&lt;tt&gt;
  693. &lt;/tt&gt;34&lt;tt&gt;
  694. &lt;/tt&gt;35&lt;tt&gt;
  695. &lt;/tt&gt;36&lt;tt&gt;
  696. &lt;/tt&gt;37&lt;tt&gt;
  697. &lt;/tt&gt;38&lt;tt&gt;
  698. &lt;/tt&gt;39&lt;tt&gt;
  699. &lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
  700. &lt;/tt&gt;41&lt;tt&gt;
  701. &lt;/tt&gt;42&lt;tt&gt;
  702. &lt;/tt&gt;43&lt;tt&gt;
  703. &lt;/tt&gt;44&lt;tt&gt;
  704. &lt;/tt&gt;45&lt;tt&gt;
  705. &lt;/tt&gt;46&lt;tt&gt;
  706. &lt;/tt&gt;47&lt;tt&gt;
  707. &lt;/tt&gt;48&lt;tt&gt;
  708. &lt;/tt&gt;49&lt;tt&gt;
  709. &lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
  710. &lt;/tt&gt;51&lt;tt&gt;
  711. &lt;/tt&gt;52&lt;tt&gt;
  712. &lt;/tt&gt;53&lt;tt&gt;
  713. &lt;/tt&gt;54&lt;tt&gt;
  714. &lt;/tt&gt;55&lt;tt&gt;
  715. &lt;/tt&gt;56&lt;tt&gt;
  716. &lt;/tt&gt;57&lt;tt&gt;
  717. &lt;/tt&gt;58&lt;tt&gt;
  718. &lt;/tt&gt;59&lt;tt&gt;
  719. &lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
  720. &lt;/tt&gt;61&lt;tt&gt;
  721. &lt;/tt&gt;62&lt;tt&gt;
  722. &lt;/tt&gt;63&lt;tt&gt;
  723. &lt;/tt&gt;64&lt;tt&gt;
  724. &lt;/tt&gt;65&lt;tt&gt;
  725. &lt;/tt&gt;66&lt;tt&gt;
  726. &lt;/tt&gt;67&lt;tt&gt;
  727. &lt;/tt&gt;68&lt;tt&gt;
  728. &lt;/tt&gt;69&lt;tt&gt;
  729. &lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
  730. &lt;/tt&gt;71&lt;tt&gt;
  731. &lt;/tt&gt;72&lt;tt&gt;
  732. &lt;/tt&gt;73&lt;tt&gt;
  733. &lt;/tt&gt;74&lt;tt&gt;
  734. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  735.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;require &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;webrick&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  736. &lt;/tt&gt;require &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;logger&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  737. &lt;/tt&gt;&lt;tt&gt;
  738. &lt;/tt&gt;puts &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;lt;&amp;lt;-BANNER&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;&quot;&gt;&lt;tt&gt;
  739. &lt;/tt&gt;&lt;tt&gt;
  740. &lt;/tt&gt;   ,~~.,''&amp;quot;'`'.~~.&lt;tt&gt;
  741. &lt;/tt&gt;  : {` .- _ -. '} ;&lt;tt&gt;
  742. &lt;/tt&gt;   `:   O(_)O   ;'&lt;tt&gt;
  743. &lt;/tt&gt;    ';  ._|_,  ;`   i am starting the server&lt;tt&gt;
  744. &lt;/tt&gt;     '`-.&lt;/span&gt;&lt;span style=&quot;color:#b0b&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;&quot;&gt;_/,.'`&lt;tt&gt;
  745. &lt;/tt&gt;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&lt;tt&gt;
  746. &lt;/tt&gt;BANNER&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  747. &lt;/tt&gt;&lt;tt&gt;
  748. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color:#B06;font-weight:bold&quot;&gt;DropwizardLogger&lt;/span&gt; &amp;lt; &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;Logger&lt;/span&gt;&lt;tt&gt;
  749. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;initialize&lt;/span&gt;(label, *args)&lt;tt&gt;
  750. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;super&lt;/span&gt;(*args)&lt;tt&gt;
  751. &lt;/tt&gt;    &lt;span style=&quot;color:#33B&quot;&gt;@label&lt;/span&gt; = label&lt;tt&gt;
  752. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  753. &lt;/tt&gt;&lt;tt&gt;
  754. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;format_message&lt;/span&gt;(severity, timestamp, progname, msg)&lt;tt&gt;
  755. &lt;/tt&gt;    &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;%-5s [%s] %s: %s&lt;/span&gt;&lt;span style=&quot;color:#b0b&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; % [&lt;tt&gt;
  756. &lt;/tt&gt;      severity,&lt;tt&gt;
  757. &lt;/tt&gt;      timestamp.utc.strftime(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;%Y-%m-%d %H:%M:%S,%3N&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;),&lt;tt&gt;
  758. &lt;/tt&gt;      &lt;span style=&quot;color:#33B&quot;&gt;@label&lt;/span&gt;,&lt;tt&gt;
  759. &lt;/tt&gt;      msg2str(msg),&lt;tt&gt;
  760. &lt;/tt&gt;    ]&lt;tt&gt;
  761. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  762. &lt;/tt&gt;&lt;tt&gt;
  763. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;msg2str&lt;/span&gt;(msg)&lt;tt&gt;
  764. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;case&lt;/span&gt; msg&lt;tt&gt;
  765. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;when&lt;/span&gt; &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;String&lt;/span&gt;&lt;tt&gt;
  766. &lt;/tt&gt;      msg&lt;tt&gt;
  767. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;when&lt;/span&gt; &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;Exception&lt;/span&gt;&lt;tt&gt;
  768. &lt;/tt&gt;      (&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;%s: %s&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; % [msg.class, msg.message]) +&lt;tt&gt;
  769. &lt;/tt&gt;        (msg.backtrace ? msg.backtrace.map {|x| &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#b0b&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;&quot;&gt;! &lt;/span&gt;&lt;span style=&quot;background:#ddd;color:black&quot;&gt;&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;#{&lt;/span&gt;x&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }.join : &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
  770. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;else&lt;/span&gt;&lt;tt&gt;
  771. &lt;/tt&gt;      msg.inspect&lt;tt&gt;
  772. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  773. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  774. &lt;/tt&gt;&lt;tt&gt;
  775. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#038;font-weight:bold&quot;&gt;self&lt;/span&gt;.&lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;webrick_format&lt;/span&gt;(label)&lt;tt&gt;
  776. &lt;/tt&gt;    &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;INFO  [%{%Y-%m-%d %H:%M:%S,%3N}t] &lt;/span&gt;&lt;span style=&quot;background:#ddd;color:black&quot;&gt;&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;#{&lt;/span&gt;label&lt;span style=&quot;background:#ddd;font-weight:bold;color:#666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;: %m %U %s&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  777. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  778. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  779. &lt;/tt&gt;&lt;tt&gt;
  780. &lt;/tt&gt;server = &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;WEBrick&lt;/span&gt;::&lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;HTTPServer&lt;/span&gt;.new \&lt;tt&gt;
  781. &lt;/tt&gt;  &lt;span style=&quot;color:#A60&quot;&gt;:Port&lt;/span&gt;      =&amp;gt; &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;8000&lt;/span&gt;,&lt;tt&gt;
  782. &lt;/tt&gt;  &lt;span style=&quot;color:#A60&quot;&gt;:Logger&lt;/span&gt;    =&amp;gt; &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;DropwizardLogger&lt;/span&gt;.new(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;webrick&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span style=&quot;color:#d70;font-weight:bold&quot;&gt;$stdout&lt;/span&gt;).tap {|x|&lt;tt&gt;
  783. &lt;/tt&gt;                  x.level = &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;Logger&lt;/span&gt;::&lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;INFO&lt;/span&gt;&lt;tt&gt;
  784. &lt;/tt&gt;                },&lt;tt&gt;
  785. &lt;/tt&gt;  &lt;span style=&quot;color:#A60&quot;&gt;:AccessLog&lt;/span&gt; =&amp;gt; [[&lt;span style=&quot;color:#d70;font-weight:bold&quot;&gt;$stdout&lt;/span&gt;, &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;DropwizardLogger&lt;/span&gt;.webrick_format(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;webrick&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)]]&lt;tt&gt;
  786. &lt;/tt&gt;&lt;tt&gt;
  787. &lt;/tt&gt;&lt;span style=&quot;color:#d70;font-weight:bold&quot;&gt;$logger&lt;/span&gt; = &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;DropwizardLogger&lt;/span&gt;.new(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span style=&quot;color:#d70;font-weight:bold&quot;&gt;$stdout&lt;/span&gt;)&lt;tt&gt;
  788. &lt;/tt&gt;&lt;tt&gt;
  789. &lt;/tt&gt;server.mount_proc &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;/fail&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;do&lt;/span&gt; |req, res|&lt;tt&gt;
  790. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;begin&lt;/span&gt;&lt;tt&gt;
  791. &lt;/tt&gt;    raise &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;fail&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  792. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;rescue&lt;/span&gt; =&amp;gt; e&lt;tt&gt;
  793. &lt;/tt&gt;    &lt;span style=&quot;color:#d70;font-weight:bold&quot;&gt;$logger&lt;/span&gt;.error(e)&lt;tt&gt;
  794. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  795. &lt;/tt&gt;  res.body = &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;failed&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  796. &lt;/tt&gt;  res.status = &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;500&lt;/span&gt;&lt;tt&gt;
  797. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  798. &lt;/tt&gt;&lt;tt&gt;
  799. &lt;/tt&gt;server.mount_proc &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;do&lt;/span&gt; |req, res|&lt;tt&gt;
  800. &lt;/tt&gt;  &lt;span style=&quot;color:#d70;font-weight:bold&quot;&gt;$logger&lt;/span&gt;.debug(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;&quot;&gt;hello from in the request&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
  801. &lt;/tt&gt;  res.body = &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;Hello, world!&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  802. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  803. &lt;/tt&gt;&lt;tt&gt;
  804. &lt;/tt&gt;trap &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;&quot;&gt;INT&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
  805. &lt;/tt&gt;  server.shutdown&lt;tt&gt;
  806. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  807. &lt;/tt&gt;&lt;tt&gt;
  808. &lt;/tt&gt;server.start&lt;tt&gt;
  809. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  810. &lt;/tr&gt;&lt;/table&gt;</content><category term="code" /><category term="dropwizard" /><category term="ruby" /><category term="webrick" /><summary type="html">Wouldn&amp;#8217;t it be great if instead of webrick logs looking like:
  811.  1
  812. 2
  813. 3
  814. 4
  815. 5
  816. 6
  817. 7
  818. 8
  819. 9
  820. 10
  821. 11
  822. 12
  823. 13
  824. 14
  825. 15
  826. 16
  827. 17
  828.  
  829.  &amp;gt; ruby server.rb
  830. [2014-08-17 15:29:10] INFO  WEBrick 1.3.1
  831. [2014-08-17 15:29:10] INFO  ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0]
  832. [2014-08-17 15:29:10] INFO  WEBrick::HTTPServer#start: pid=17304 port=8000
  833. D, [2014-08-17T15:29:11.452223 #17304] DEBUG -- : hello from in the request
  834. localhost - - [17/Aug/2014:15:29:11 PDT] &amp;quot;GET / HTTP/1.1&amp;quot; 200 13
  835. - -&amp;gt; /
  836. E, [2014-08-17T15:29:12.787505 #17304] ERROR -- : fail (RuntimeError)
  837. server.rb:57:in `block in &amp;lt;main&amp;gt;'
  838. /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `call'
  839. /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `do_GET'
  840. /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/abstract.rb:106:in `service'
  841. /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service'
  842. /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run'
  843. /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/server.rb:295:in `block in start_thread'
  844. localhost - - [17/Aug/2014:15:29:12 PDT] &amp;quot;GET /fail HTTP/1.1&amp;quot; 500 6
  845. - -&amp;gt; /fail
  846.  
  847.  
  848. They looked like:
  849.  1
  850. 2
  851. 3
  852. 4
  853. 5
  854. 6
  855. 7
  856. 8
  857. 9
  858. 10
  859. 11
  860. 12
  861. 13
  862. 14
  863. 15
  864. 16
  865. 17
  866. 18
  867. 19
  868. 20
  869. 21
  870. 22
  871.  
  872.  &amp;gt; ruby server.rb
  873.  
  874.   ,~~.,''&amp;quot;'`'.~~.
  875.  : {` .- _ -. '} ;
  876.   `:   O(_)O   ;'
  877.    ';  ._|_,  ;`   i am starting the server
  878.     '`-.\_/,.'`
  879.  
  880. INFO  [2014-08-17 22:28:13,186] webrick: WEBrick 1.3.1
  881. INFO  [2014-08-17 22:28:13,186] webrick: ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0]
  882. INFO  [2014-08-17 22:28:13,187] webrick: WEBrick::HTTPServer#start: pid=17253 port=8000
  883. DEBUG [2014-08-17 22:28:14,738] app: hello from in the request
  884. INFO  [2014-08-17 15:28:14,736] webrick: GET / 200
  885. ERROR [2014-08-17 22:28:15,603] app: RuntimeError: fail
  886. ! server.rb:57:in `block in &amp;lt;main&amp;gt;'
  887. ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `call'
  888. ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `do_GET'
  889. ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/abstract.rb:106:in `service'
  890. ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service'
  891. ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run'
  892. ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/server.rb:295:in `block in start_thread'
  893. INFO  [2014-08-17 15:28:15,602] webrick: GET /fail 500
  894.  
  895.  
  896. I thought so, hence:
  897.  1
  898. 2
  899. 3
  900. 4
  901. 5
  902. 6
  903. 7
  904. 8
  905. 9
  906. 10
  907. 11
  908. 12
  909. 13
  910. 14
  911. 15
  912. 16
  913. 17
  914. 18
  915. 19
  916. 20
  917. 21
  918. 22
  919. 23
  920. 24
  921. 25
  922. 26
  923. 27
  924. 28
  925. 29
  926. 30
  927. 31
  928. 32
  929. 33
  930. 34
  931. 35
  932. 36
  933. 37
  934. 38
  935. 39
  936. 40
  937. 41
  938. 42
  939. 43
  940. 44
  941. 45
  942. 46
  943. 47
  944. 48
  945. 49
  946. 50
  947. 51
  948. 52
  949. 53
  950. 54
  951. 55
  952. 56
  953. 57
  954. 58
  955. 59
  956. 60
  957. 61
  958. 62
  959. 63
  960. 64
  961. 65
  962. 66
  963. 67
  964. 68
  965. 69
  966. 70
  967. 71
  968. 72
  969. 73
  970. 74
  971.  
  972.  require 'webrick'
  973. require 'logger'
  974.  
  975. puts &amp;lt;&amp;lt;-BANNER
  976.  
  977.   ,~~.,''&amp;quot;'`'.~~.
  978.  : {` .- _ -. '} ;
  979.   `:   O(_)O   ;'
  980.    ';  ._|_,  ;`   i am starting the server
  981.     '`-.\\_/,.'`
  982.  
  983. BANNER
  984.  
  985. class DropwizardLogger &amp;lt; Logger
  986.  def initialize(label, *args)
  987.    super(*args)
  988.    @label = label
  989.  end
  990.  
  991.  def format_message(severity, timestamp, progname, msg)
  992.    &amp;quot;%-5s [%s] %s: %s &amp;quot; % [
  993.      severity,
  994.      timestamp.utc.strftime(&amp;quot;%Y-%m-%d %H:%M:%S,%3N&amp;quot;),
  995.      @label,
  996.      msg2str(msg),
  997.    ]
  998.  end
  999.  
  1000.  def msg2str(msg)
  1001.    case msg
  1002.    when String
  1003.      msg
  1004.    when Exception
  1005.      (&amp;quot;%s: %s&amp;quot; % [msg.class, msg.message]) +
  1006.        (msg.backtrace ? msg.backtrace.map {|x| &amp;quot; ! #{x}&amp;quot; }.join : &amp;quot;&amp;quot;)
  1007.    else
  1008.      msg.inspect
  1009.    end
  1010.  end
  1011.  
  1012.  def self.webrick_format(label)
  1013.    &amp;quot;INFO  [%{%Y-%m-%d %H:%M:%S,%3N}t] #{label}: %m %U %s&amp;quot;
  1014.  end
  1015. end
  1016.  
  1017. server = WEBrick::HTTPServer.new \
  1018.  :Port      =&amp;gt; 8000,
  1019.  :Logger    =&amp;gt; DropwizardLogger.new(&amp;quot;webrick&amp;quot;, $stdout).tap {|x|
  1020.                  x.level = Logger::INFO
  1021.                },
  1022.  :AccessLog =&amp;gt; [[$stdout, DropwizardLogger.webrick_format(&amp;quot;webrick&amp;quot;)]]
  1023.  
  1024. $logger = DropwizardLogger.new(&amp;quot;app&amp;quot;, $stdout)
  1025.  
  1026. server.mount_proc '/fail' do |req, res|
  1027.  begin
  1028.    raise 'fail'
  1029.  rescue =&amp;gt; e
  1030.    $logger.error(e)
  1031.  end
  1032.  res.body = &amp;quot;failed&amp;quot;
  1033.  res.status = 500
  1034. end
  1035.  
  1036. server.mount_proc '/' do |req, res|
  1037.  $logger.debug(&amp;quot;hello from in the request&amp;quot;)
  1038.  res.body = 'Hello, world!'
  1039. end
  1040.  
  1041. trap 'INT' do
  1042.  server.shutdown
  1043. end
  1044.  
  1045. server.start</summary></entry><entry><title type="html">Querying consul with range</title><link href="http://localhost:4000/2014/08/16/querying-consul-with-range/" rel="alternate" type="text/html" title="Querying consul with range" /><published>2014-08-16T23:32:00+00:00</published><updated>2014-08-16T23:32:00+00:00</updated><id>http://localhost:4000/2014/08/16/querying-consul-with-range</id><content type="html" xml:base="http://localhost:4000/2014/08/16/querying-consul-with-range/">&lt;p&gt;&lt;em&gt;Disclaimer: this has not been tried in a production environment. It is a weekend hack.&lt;/em&gt;&lt;/p&gt;
  1046. &lt;p&gt;&lt;a href=&quot;http://www.consul.io/&quot;&gt;Consul&lt;/a&gt; is a highly available, datacenter aware, service discovery mechanism. &lt;a href=&quot;http://godoc.org/github.com/xaviershay/grange&quot;&gt;Range&lt;/a&gt; is a query language for selecting information out of arbitrary, self-referential metadata. I combined the two!&lt;/p&gt;
  1047. &lt;p&gt;Start by firing up a two node consul cluster, per the &lt;a href=&quot;http://www.consul.io/intro/getting-started/join.html&quot;&gt;getting started guide&lt;/a&gt;. On the master node, grab the &lt;a href=&quot;https://github.com/xaviershay/grange-server/pull/4&quot;&gt;&lt;code&gt;consul&lt;/code&gt; branch of grange-server&lt;/a&gt; and run it with the following config:&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  1048.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  1049. &lt;/tt&gt;2&lt;tt&gt;
  1050. &lt;/tt&gt;3&lt;tt&gt;
  1051. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  1052.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;[rangeserver]&lt;tt&gt;
  1053. &lt;/tt&gt;loglevel=DEBUG&lt;tt&gt;
  1054. &lt;/tt&gt;consul=true&lt;tt&gt;
  1055. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  1056. &lt;/tr&gt;&lt;/table&gt;
  1057. &lt;p&gt;(It could run against any consul agent, but it&amp;#8217;s easier to demo on the master node.)&lt;/p&gt;
  1058. &lt;p&gt;Querying range, we already see a consul cluster, &lt;code&gt;cluster&lt;/code&gt;. This is a default service containing the consul servers.&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  1059.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  1060. &lt;/tt&gt;2&lt;tt&gt;
  1061. &lt;/tt&gt;3&lt;tt&gt;
  1062. &lt;/tt&gt;4&lt;tt&gt;
  1063. &lt;/tt&gt;5&lt;tt&gt;
  1064. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  1065.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;&amp;gt; export RANGE_HOST=172.20.20.10&lt;tt&gt;
  1066. &lt;/tt&gt;&amp;gt; erg &amp;quot;allclusters()&amp;quot;&lt;tt&gt;
  1067. &lt;/tt&gt;consul&lt;tt&gt;
  1068. &lt;/tt&gt;&amp;gt; erg &amp;quot;%consul&amp;quot;&lt;tt&gt;
  1069. &lt;/tt&gt;agent-one&lt;tt&gt;
  1070. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  1071. &lt;/tr&gt;&lt;/table&gt;
  1072. &lt;p&gt;Add a new service to the agents, and it shows up in range!&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  1073.  &lt;td class=&quot;line_numbers&quot; title=&quot;click to toggle&quot; onclick=&quot;with (this.firstChild.style) { display = (display == '') ? 'none' : '' }&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
  1074. &lt;/tt&gt;2&lt;tt&gt;
  1075. &lt;/tt&gt;3&lt;tt&gt;
  1076. &lt;/tt&gt;4&lt;tt&gt;
  1077. &lt;/tt&gt;5&lt;tt&gt;
  1078. &lt;/tt&gt;6&lt;tt&gt;
  1079. &lt;/tt&gt;7&lt;tt&gt;
  1080. &lt;/tt&gt;8&lt;tt&gt;
  1081. &lt;/tt&gt;9&lt;tt&gt;
  1082. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  1083. &lt;/tt&gt;11&lt;tt&gt;
  1084. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  1085.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;n2&amp;gt; curl -v -X PUT --data '{&amp;quot;name&amp;quot;: &amp;quot;web&amp;quot;, &amp;quot;port&amp;quot;: 80}' http://localhost:8500/v1/agent/service/register&lt;tt&gt;
  1086. &lt;/tt&gt;&lt;tt&gt;
  1087. &lt;/tt&gt;&amp;gt; erg &amp;quot;allclusters()&amp;quot;&lt;tt&gt;
  1088. &lt;/tt&gt;consul,web&lt;tt&gt;
  1089. &lt;/tt&gt;&amp;gt; erg &amp;quot;%web&amp;quot;&lt;tt&gt;
  1090. &lt;/tt&gt;agent-two&lt;tt&gt;
  1091. &lt;/tt&gt;&lt;tt&gt;
  1092. &lt;/tt&gt;n1&amp;gt; curl -v -X PUT --data '{&amp;quot;name&amp;quot;: &amp;quot;web&amp;quot;, &amp;quot;port&amp;quot;: 80}' http://localhost:8500/v1/agent/service/register&lt;tt&gt;
  1093. &lt;/tt&gt;&lt;tt&gt;
  1094. &lt;/tt&gt;&amp;gt; erg &amp;quot;%web&amp;quot;&lt;tt&gt;
  1095. &lt;/tt&gt;agent-one,agent-two&lt;tt&gt;
  1096. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  1097. &lt;/tr&gt;&lt;/table&gt;
  1098. &lt;p&gt;Though eventually consistent, range is a big improvement over the consul &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for quick ad-hoc queries against your production layout, particularly when combined with other metadata. How many nodes are running redis? What services are running on a particular rack?&lt;/p&gt;
  1099. &lt;p&gt;This is just a proof of concept for now, but I&amp;#8217;m excited about the potential. To be useable it needs to be tested against production sized clusters, better handling of error conditions, and some code review (in particular around handling cluster state changes).&lt;/p&gt;</content><category term="code" /><category term="consul" /><category term="range" /><summary type="html">Disclaimer: this has not been tried in a production environment. It is a weekend hack.
  1100. Consul is a highly available, datacenter aware, service discovery mechanism. Range is a query language for selecting information out of arbitrary, self-referential metadata. I combined the two!
  1101. Start by firing up a two node consul cluster, per the getting started guide. On the master node, grab the consul branch of grange-server and run it with the following config:
  1102.  1
  1103. 2
  1104. 3
  1105.  
  1106.  [rangeserver]
  1107. loglevel=DEBUG
  1108. consul=true
  1109.  
  1110.  
  1111. (It could run against any consul agent, but it&amp;#8217;s easier to demo on the master node.)
  1112. Querying range, we already see a consul cluster, cluster. This is a default service containing the consul servers.
  1113.  1
  1114. 2
  1115. 3
  1116. 4
  1117. 5
  1118.  
  1119.  &amp;gt; export RANGE_HOST=172.20.20.10
  1120. &amp;gt; erg &amp;quot;allclusters()&amp;quot;
  1121. consul
  1122. &amp;gt; erg &amp;quot;%consul&amp;quot;
  1123. agent-one
  1124.  
  1125.  
  1126. Add a new service to the agents, and it shows up in range!
  1127.  1
  1128. 2
  1129. 3
  1130. 4
  1131. 5
  1132. 6
  1133. 7
  1134. 8
  1135. 9
  1136. 10
  1137. 11
  1138.  
  1139.  n2&amp;gt; curl -v -X PUT --data '{&amp;quot;name&amp;quot;: &amp;quot;web&amp;quot;, &amp;quot;port&amp;quot;: 80}' http://localhost:8500/v1/agent/service/register
  1140.  
  1141. &amp;gt; erg &amp;quot;allclusters()&amp;quot;
  1142. consul,web
  1143. &amp;gt; erg &amp;quot;%web&amp;quot;
  1144. agent-two
  1145.  
  1146. n1&amp;gt; curl -v -X PUT --data '{&amp;quot;name&amp;quot;: &amp;quot;web&amp;quot;, &amp;quot;port&amp;quot;: 80}' http://localhost:8500/v1/agent/service/register
  1147.  
  1148. &amp;gt; erg &amp;quot;%web&amp;quot;
  1149. agent-one,agent-two
  1150.  
  1151.  
  1152. Though eventually consistent, range is a big improvement over the consul HTTP API for quick ad-hoc queries against your production layout, particularly when combined with other metadata. How many nodes are running redis? What services are running on a particular rack?
  1153. This is just a proof of concept for now, but I&amp;#8217;m excited about the potential. To be useable it needs to be tested against production sized clusters, better handling of error conditions, and some code review (in particular around handling cluster state changes).</summary></entry></feed>
  1154.  
Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda