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"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://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>2021-04-02T00:15:12+00:00</updated><id>http://localhost:4000/feed.xml</id><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
  2. Pattern&lt;/a&gt; in D3, but I couldn’t get it
  3. working. I knew I was missing something obvious, but how to figure out what?&lt;/p&gt;
  4.  
  5. &lt;p&gt;Because I was dealing with nested attributes, I was assigning the selections
  6. to variables and then merging them later, so ended up with this heavily
  7. simplified (and broken) code to display a list of tiles:&lt;/p&gt;
  8.  
  9. &lt;div class=&quot;language-javascript highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  10.  &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)
  11. &lt;span class=&quot;no&quot;&gt; 2&lt;/span&gt;
  12. &lt;span class=&quot;no&quot;&gt; 3&lt;/span&gt; let tilesEnter = tiles.enter()
  13. &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;)
  14. &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;)
  15. &lt;span class=&quot;no&quot;&gt; 6&lt;/span&gt;
  16. &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)
  17. &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)
  18. &lt;span class=&quot;no&quot;&gt; 9&lt;/span&gt;
  19. &lt;span class=&quot;no&quot;&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; let contentEnter = tilesEnter
  20. &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;)
  21. &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;)
  22. &lt;span class=&quot;no&quot;&gt;13&lt;/span&gt;
  23. &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)
  24. &lt;span class=&quot;no&quot;&gt;15&lt;/span&gt;   html(d =&amp;gt; d.content)
  25. &lt;/pre&gt;&lt;/div&gt;
  26. &lt;/div&gt;
  27. &lt;/div&gt;
  28.  
  29. &lt;p&gt;When I updated the data, the content of the tile in the child element updated,
  30. but the color at the root level did not!&lt;/p&gt;
  31.  
  32. &lt;p&gt;I tried a number of debugging approaches, but the one that I found easiest to
  33. wrap my head around, and that eventually led me to a solution, was using the
  34. &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
  35. many elements where in each selection.&lt;/p&gt;
  36.  
  37. &lt;div class=&quot;language-javascript highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  38.  &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())
  39. &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())
  40. &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())
  41. &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())
  42. &lt;/pre&gt;&lt;/div&gt;
  43. &lt;/div&gt;
  44. &lt;/div&gt;
  45.  
  46. &lt;p&gt;This allowed me to verify that for the second working case (for data with
  47. four elements) that the enter/update selections went from 4 and 0
  48. respectively to 0 and 4 when data was updated. For the first case, the update
  49. selection was always zero, and this led me to notice the extra
  50. &lt;code&gt;select('.tile')&lt;/code&gt; shouldn’t be there for the root case, since we’re already
  51. on that selection from the &lt;code&gt;selectAll&lt;/code&gt; in the initial setup!&lt;/p&gt;
  52.  
  53. &lt;p&gt;I found logging the entire selection to not be as useful, because it’s
  54. confusing what its internal state actually means.&lt;/p&gt;</content><author><name></name></author><category term="code" /><category term="javascript" /><category term="d3" /><summary type="html">Yesterday I was learning about the relatively new General Update Pattern in D3, but I couldn’t get it 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;
  55. (boilerplate redacted for brevity):&lt;/p&gt;
  56.  
  57. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  58.  &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
  59. &lt;span class=&quot;no&quot;&gt;2&lt;/span&gt;
  60. &lt;span class=&quot;no&quot;&gt;3&lt;/span&gt; someApi = return NoContent
  61. &lt;/pre&gt;&lt;/div&gt;
  62. &lt;/div&gt;
  63. &lt;/div&gt;
  64.  
  65. &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
  66. &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;
  67.  
  68. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  69.  &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)
  70. &lt;span class=&quot;no&quot;&gt; 2&lt;/span&gt;
  71. &lt;span class=&quot;no&quot;&gt; 3&lt;/span&gt; type LastModifiedHeader = Header &amp;quot;Last-Modified&amp;quot; UTCTime
  72. &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)
  73. &lt;span class=&quot;no&quot;&gt; 5&lt;/span&gt;
  74. &lt;span class=&quot;no&quot;&gt; 6&lt;/span&gt; someApi = do
  75. &lt;span class=&quot;no&quot;&gt; 7&lt;/span&gt;   now &amp;lt;- getCurrentTime
  76. &lt;span class=&quot;no&quot;&gt; 8&lt;/span&gt;   addHeader now
  77. &lt;span class=&quot;no&quot;&gt; 9&lt;/span&gt;   return NoContent
  78. &lt;/pre&gt;&lt;/div&gt;
  79. &lt;/div&gt;
  80. &lt;/div&gt;
  81.  
  82. &lt;p&gt;Unfortunately, this returns the time in the wrong format!&lt;/p&gt;
  83.  
  84. &lt;pre&gt;&lt;code&gt;&amp;gt; curl -I localhost/some-api | grep Last-Modified
  85. Last-Modified: 2018-09-30T19:56:39Z
  86. &lt;/code&gt;&lt;/pre&gt;
  87.  
  88. &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
  89. 1123&lt;/a&gt;. We can
  90. fix this with a &lt;code&gt;newtype&lt;/code&gt; that wraps the
  91. formatting functions available in &lt;code&gt;Data.Time.Format&lt;/code&gt;:&lt;/p&gt;
  92.  
  93. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  94.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt; 1&lt;/span&gt; {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  95. &lt;span class=&quot;no&quot;&gt; 2&lt;/span&gt;
  96. &lt;span class=&quot;no&quot;&gt; 3&lt;/span&gt; import Data.ByteString (pack)
  97. &lt;span class=&quot;no&quot;&gt; 4&lt;/span&gt; import Data.Time.Clock (UTCTime, getCurrentTime)
  98. &lt;span class=&quot;no&quot;&gt; 5&lt;/span&gt; import Data.Time.Format (formatTime, defaultTimeLocale, rfc1123DateFormat)
  99. &lt;span class=&quot;no&quot;&gt; 6&lt;/span&gt;
  100. &lt;span class=&quot;no&quot;&gt; 7&lt;/span&gt; newtype RFC1123Time = RFC1123Time UTCTime
  101. &lt;span class=&quot;no&quot;&gt; 8&lt;/span&gt;   deriving (Show, FormatTime)
  102. &lt;span class=&quot;no&quot;&gt; 9&lt;/span&gt;
  103. &lt;span class=&quot;no&quot;&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; instance ToHttpApiData RFC1123Time where
  104. &lt;span class=&quot;no&quot;&gt;11&lt;/span&gt;   toUrlPiece = error &amp;quot;Not intended to be used in URLs&amp;quot;
  105. &lt;span class=&quot;no&quot;&gt;12&lt;/span&gt;   toHeader =
  106. &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
  107. &lt;span class=&quot;no&quot;&gt;14&lt;/span&gt;     pack . formatTime defaultTimeLocale rfc1123DateFormat
  108. &lt;span class=&quot;no&quot;&gt;15&lt;/span&gt;
  109. &lt;span class=&quot;no&quot;&gt;16&lt;/span&gt; type LastModifiedHeader = Header &amp;quot;Last-Modified&amp;quot; RFC1123Time
  110. &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)
  111. &lt;span class=&quot;no&quot;&gt;18&lt;/span&gt;
  112. &lt;span class=&quot;no&quot;&gt;19&lt;/span&gt; someApi = do
  113. &lt;span class=&quot;no&quot;&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt;   now &amp;lt;- getCurrentTime
  114. &lt;span class=&quot;no&quot;&gt;21&lt;/span&gt;   addHeader $ RFC1123Time now
  115. &lt;span class=&quot;no&quot;&gt;22&lt;/span&gt;   return NoContent
  116. &lt;/pre&gt;&lt;/div&gt;
  117. &lt;/div&gt;
  118. &lt;/div&gt;
  119.  
  120. &lt;pre&gt;&lt;code&gt;&amp;gt; curl -I localhost/some-api | grep Last-Modified
  121. Last-Modified: Sun, 30 Sep 2018 20:44:16 GMT
  122. &lt;/code&gt;&lt;/pre&gt;
  123.  
  124. &lt;p&gt;If anyone knows a simpler way, please let me know!&lt;/p&gt;
  125.  
  126. &lt;h3 id=&quot;irreverant-technical-asides&quot;&gt;Irreverant technical asides&lt;/h3&gt;
  127.  
  128. &lt;p&gt;Many implementations reference RFC822 for &lt;code&gt;Last-Modified&lt;/code&gt; format. What gives?
  129. RFC822 was updated by RFC1123, which only adds a few clauses to tighten up the
  130. definition. Most importantly, it updates the year format from 2 digits to 4!
  131. Note that
  132. &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;
  133. is technically incorrect here, specifying a four digit year.
  134. &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;
  135. gets it right.&lt;/p&gt;
  136.  
  137. &lt;p&gt;&lt;code&gt;rfc822DateFormat&lt;/code&gt; is also technically incorrect in another way: it uses the
  138. &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
  139. is not an allowed value! However,
  140. &lt;a href=&quot;https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1&quot;&gt;RFC 2616&lt;/a&gt; says
  141. “for the purposes of HTTP, GMT is exactly equal to UTC” so GMT can safely be
  142. hardcoded here since we know we always have a UTC time.&lt;/p&gt;</content><author><name></name></author><category term="code" /><category term="haskell" /><category term="servant" /><summary type="html">Given the following Servant API (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
  143. applications. In particular, I’m interested to what extent it is feasible to
  144. start an application with a “pure” API, as distinct from a typical Ruby on
  145. Rails application. This approach would limit the backend server to only API
  146. endpoints, and restrict it from any kind of HTML generation. All HTML concerns
  147. would be pushed to a frontend using something like React.&lt;/p&gt;
  148.  
  149. &lt;p&gt;I published an &lt;a href=&quot;https://github.com/xaviershay/haskell-servant-react-auth-example&quot;&gt;example
  150. application&lt;/a&gt;
  151. that demostrates this architecture using
  152. &lt;a href=&quot;http://haskell-servant.readthedocs.io/en/stable/&quot;&gt;Servant&lt;/a&gt; and
  153. &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;. In this post, I’ll detail some of the issues I
  154. came across getting this working.&lt;/p&gt;
  155.  
  156. &lt;h2 id=&quot;authentication&quot;&gt;Authentication&lt;/h2&gt;
  157.  
  158. &lt;p&gt;One difficultly I came across was how to handle third-party authentication (via
  159. Google OAuth) in this scenario when running the backend and frontend as
  160. completely separate services. A typical OAuth flow requires server side calls
  161. and interactions that don’t work when the flow is split over two different
  162. services.&lt;/p&gt;
  163.  
  164. &lt;p&gt;Google provides an &lt;a href=&quot;https://developers.google.com/identity/protocols/OAuth2UserAgent&quot;&gt;OAuth flow for Web
  165. Applications&lt;/a&gt;
  166. that addresses the first issue. The hard part is how to verify that
  167. authentication in the backend.&lt;/p&gt;
  168.  
  169. &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
  170. information about the user, such as their email and granted scopes. This can be
  171. &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
  172. server&lt;/a&gt;
  173. 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
  174. endpoint&lt;/a&gt;
  175. to keep it current.&lt;/p&gt;
  176.  
  177. &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;
  178.  
  179. &lt;h2 id=&quot;cors&quot;&gt;CORS&lt;/h2&gt;
  180.  
  181. &lt;p&gt;Requests between applications on different hosts have to negotiate CORS
  182. correctly. This could be mitigated by running a reverse proxy in front of both
  183. services and presenting them at a single domain, but I wanted to see if I could
  184. make it work without this.&lt;/p&gt;
  185.  
  186. &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;
  187.  
  188. &lt;p&gt;That would be sufficient for “simple” requests, but for since our API uses both
  189. a non-simple content type (&lt;code&gt;application/json&lt;/code&gt;) and the &lt;code&gt;Authorization&lt;/code&gt; header,
  190. they need to be added to the default policy:&lt;/p&gt;
  191.  
  192. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  193.  &lt;div class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;1&lt;/span&gt; corsPolicy = simpleCorsResourcePolicy
  194. &lt;span class=&quot;no&quot;&gt;2&lt;/span&gt;                { corsRequestHeaders = [ &amp;quot;authorization&amp;quot;, &amp;quot;content-type&amp;quot; ]
  195. &lt;span class=&quot;no&quot;&gt;3&lt;/span&gt;                }
  196. &lt;/pre&gt;&lt;/div&gt;
  197. &lt;/div&gt;
  198. &lt;/div&gt;
  199.  
  200. &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
  201. preflight&lt;/a&gt;,
  202. which sends an &lt;code&gt;OPTIONS&lt;/code&gt; request to our API. The API needs to be extended to
  203. handle these requests.
  204. &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
  205. 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;
  206.  
  207. &lt;div class=&quot;language-haskell highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  208.  &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;
  209. &lt;span class=&quot;no&quot;&gt;2&lt;/span&gt;   HasForeign lang ftype (AuthProtect k :&amp;gt; api) where
  210. &lt;span class=&quot;no&quot;&gt;3&lt;/span&gt;
  211. &lt;span class=&quot;no&quot;&gt;4&lt;/span&gt;   type Foreign ftype (AuthProtect k :&amp;gt; api) = Foreign ftype api
  212. &lt;span class=&quot;no&quot;&gt;5&lt;/span&gt;
  213. &lt;span class=&quot;no&quot;&gt;6&lt;/span&gt;   foreignFor lang Proxy Proxy subR =
  214. &lt;span class=&quot;no&quot;&gt;7&lt;/span&gt;     foreignFor lang Proxy (Proxy :: Proxy api) subR
  215. &lt;/pre&gt;&lt;/div&gt;
  216. &lt;/div&gt;
  217. &lt;/div&gt;
  218.  
  219. &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
  220. this&lt;/a&gt;
  221. to include appropriate metadata so that I could use it to generate clients
  222. correctly.&lt;/p&gt;
  223.  
  224. &lt;h2 id=&quot;js-clients&quot;&gt;JS Clients&lt;/h2&gt;
  225.  
  226. &lt;p&gt;A nice thing about Servant is the ability to auto-generate client wrappers for
  227. your API. &lt;code&gt;servant-js&lt;/code&gt; provides a number of formats for this, though they
  228. 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
  229. &lt;code&gt;servant-auth&lt;/code&gt;&lt;/a&gt; nor
  230. support for ES6-style &lt;code&gt;exports&lt;/code&gt;. Rather than solve this generically, I wrote a
  231. &lt;a href=&quot;https://github.com/xaviershay/haskell-servant-react-auth-example/blob/master/api/src/JsGeneration.hs&quot;&gt;custom
  232. generator&lt;/a&gt;.
  233. For fun, it outputs an API class that allows an authorization token to be
  234. supplied in the constructor, rather than as an argument to every function:&lt;/p&gt;
  235.  
  236. &lt;div class=&quot;language-javascript highlighter-coderay&quot;&gt;&lt;div class=&quot;CodeRay&quot;&gt;
  237.  &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);
  238. &lt;span class=&quot;no&quot;&gt;2&lt;/span&gt; api.getEmail();
  239. &lt;/pre&gt;&lt;/div&gt;
  240. &lt;/div&gt;
  241. &lt;/div&gt;
  242.  
  243. &lt;p&gt;I’m not sure what the best way to distribute this API is. Currently, the
  244. example writes out a file in the frontend’s source tree. This works great for
  245. development, but for production I would consider either a dedicated build step
  246. in packaging, or serving the JS up directly from the API server.&lt;/p&gt;
  247.  
  248. &lt;p&gt;Aside from this generated client, I didn’t do anything particularly interesting
  249. on the React front. The app included in the example is very simple.&lt;/p&gt;
  250.  
  251. &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
  252.  
  253. &lt;p&gt;This wasn’t a big enough project to draw any serious conclusions about the
  254. approach. It is evident however that Servant still has a couple of rough edges
  255. 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;
  256.  
  257. &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><author><name></name></author><category term="code" /><category term="haskell" /><category term="servant" /><summary type="html">Recently I’ve been experimenting with different ways of building web applications. In particular, I’m interested to what extent it is feasible to start an application with a “pure” API, as distinct from a typical Ruby on Rails application. This approach would limit the backend server to only API endpoints, and restrict it from any kind of HTML generation. All HTML concerns 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
  258. some uncounted on Bitbucket). I’ve continued on the RSpec core team, though the
  259. project is mostly stable and I haven’t been particularly active. I did find
  260. time to experiment with some new things however:&lt;/p&gt;
  261.  
  262. &lt;ul&gt;
  263.  &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;
  264.  &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;
  265.  &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;
  266.  &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;
  267. &lt;/ul&gt;
  268.  
  269. &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;
  270.  
  271. &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><author><name></name></author><category term="code" /><summary type="html">This was a light year for open source contribution, 168 by Github’s count (and some uncounted on Bitbucket). I’ve continued on the RSpec core team, though the project is mostly stable and I haven’t been particularly active. I did find 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;
  272. &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;
  273.  &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;
  274. &lt;/tt&gt;2&lt;tt&gt;
  275. &lt;/tt&gt;3&lt;tt&gt;
  276. &lt;/tt&gt;4&lt;tt&gt;
  277. &lt;/tt&gt;5&lt;tt&gt;
  278. &lt;/tt&gt;6&lt;tt&gt;
  279. &lt;/tt&gt;7&lt;tt&gt;
  280. &lt;/tt&gt;8&lt;tt&gt;
  281. &lt;/tt&gt;9&lt;tt&gt;
  282. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  283. &lt;/tt&gt;11&lt;tt&gt;
  284. &lt;/tt&gt;12&lt;tt&gt;
  285. &lt;/tt&gt;13&lt;tt&gt;
  286. &lt;/tt&gt;14&lt;tt&gt;
  287. &lt;/tt&gt;15&lt;tt&gt;
  288. &lt;/tt&gt;16&lt;tt&gt;
  289. &lt;/tt&gt;17&lt;tt&gt;
  290. &lt;/tt&gt;18&lt;tt&gt;
  291. &lt;/tt&gt;19&lt;tt&gt;
  292. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  293. &lt;/tt&gt;21&lt;tt&gt;
  294. &lt;/tt&gt;22&lt;tt&gt;
  295. &lt;/tt&gt;23&lt;tt&gt;
  296. &lt;/tt&gt;24&lt;tt&gt;
  297. &lt;/tt&gt;25&lt;tt&gt;
  298. &lt;/tt&gt;26&lt;tt&gt;
  299. &lt;/tt&gt;27&lt;tt&gt;
  300. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  301.  &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;
  302. &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;
  303. &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;
  304. &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;
  305. &lt;/tt&gt;      post.slug&lt;tt&gt;
  306. &lt;/tt&gt;    ]&lt;tt&gt;
  307. &lt;/tt&gt;&lt;tt&gt;
  308. &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;
  309. &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;
  310. &lt;/tt&gt;&lt;tt&gt;
  311. &lt;/tt&gt;    puts filename&lt;tt&gt;
  312. &lt;/tt&gt;&lt;tt&gt;
  313. &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;
  314. &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;
  315. &lt;/tt&gt;layout: post&lt;tt&gt;
  316. &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;
  317. &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;
  318. &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;
  319. &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;
  320. &lt;/tt&gt;{% raw %}&lt;tt&gt;
  321. &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;
  322. &lt;/tt&gt;{% endraw %}&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&lt;tt&gt;
  323. &lt;/tt&gt;    EOS&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  324. &lt;/tt&gt;&lt;tt&gt;
  325. &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;
  326. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  327. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  328. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  329. &lt;/tr&gt;&lt;/table&gt;
  330. &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;
  331.  &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;
  332. &lt;/tt&gt;2&lt;tt&gt;
  333. &lt;/tt&gt;3&lt;tt&gt;
  334. &lt;/tt&gt;4&lt;tt&gt;
  335. &lt;/tt&gt;5&lt;tt&gt;
  336. &lt;/tt&gt;6&lt;tt&gt;
  337. &lt;/tt&gt;7&lt;tt&gt;
  338. &lt;/tt&gt;8&lt;tt&gt;
  339. &lt;/tt&gt;9&lt;tt&gt;
  340. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  341. &lt;/tt&gt;11&lt;tt&gt;
  342. &lt;/tt&gt;12&lt;tt&gt;
  343. &lt;/tt&gt;13&lt;tt&gt;
  344. &lt;/tt&gt;14&lt;tt&gt;
  345. &lt;/tt&gt;15&lt;tt&gt;
  346. &lt;/tt&gt;16&lt;tt&gt;
  347. &lt;/tt&gt;17&lt;tt&gt;
  348. &lt;/tt&gt;18&lt;tt&gt;
  349. &lt;/tt&gt;19&lt;tt&gt;
  350. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  351. &lt;/tt&gt;21&lt;tt&gt;
  352. &lt;/tt&gt;22&lt;tt&gt;
  353. &lt;/tt&gt;23&lt;tt&gt;
  354. &lt;/tt&gt;24&lt;tt&gt;
  355. &lt;/tt&gt;25&lt;tt&gt;
  356. &lt;/tt&gt;26&lt;tt&gt;
  357. &lt;/tt&gt;27&lt;tt&gt;
  358. &lt;/tt&gt;28&lt;tt&gt;
  359. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  360.  &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;
  361. &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;
  362. &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;
  363. &lt;/tt&gt;&lt;tt&gt;
  364. &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;
  365. &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;
  366. &lt;/tt&gt;    safe &lt;span style=&quot;color:#038;font-weight:bold&quot;&gt;true&lt;/span&gt;&lt;tt&gt;
  367. &lt;/tt&gt;    priority &lt;span style=&quot;color:#A60&quot;&gt;:low&lt;/span&gt;&lt;tt&gt;
  368. &lt;/tt&gt;&lt;tt&gt;
  369. &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;
  370. &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;
  371. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  372. &lt;/tt&gt;&lt;tt&gt;
  373. &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;
  374. &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;
  375. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  376. &lt;/tt&gt;&lt;tt&gt;
  377. &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;
  378. &lt;/tt&gt;      &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;Lesstile&lt;/span&gt;.format_as_xhtml(&lt;tt&gt;
  379. &lt;/tt&gt;        content,&lt;tt&gt;
  380. &lt;/tt&gt;        &lt;span style=&quot;color:#A60&quot;&gt;:text_formatter&lt;/span&gt; =&amp;gt; lambda {|text|&lt;tt&gt;
  381. &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;
  382. &lt;/tt&gt;        },&lt;tt&gt;
  383. &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;
  384. &lt;/tt&gt;      )&lt;tt&gt;
  385. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  386. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  387. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  388. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  389. &lt;/tr&gt;&lt;/table&gt;
  390. &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;
  391.  &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;
  392. &lt;/tt&gt;2&lt;tt&gt;
  393. &lt;/tt&gt;3&lt;tt&gt;
  394. &lt;/tt&gt;4&lt;tt&gt;
  395. &lt;/tt&gt;5&lt;tt&gt;
  396. &lt;/tt&gt;6&lt;tt&gt;
  397. &lt;/tt&gt;7&lt;tt&gt;
  398. &lt;/tt&gt;8&lt;tt&gt;
  399. &lt;/tt&gt;9&lt;tt&gt;
  400. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  401. &lt;/tt&gt;11&lt;tt&gt;
  402. &lt;/tt&gt;12&lt;tt&gt;
  403. &lt;/tt&gt;13&lt;tt&gt;
  404. &lt;/tt&gt;14&lt;tt&gt;
  405. &lt;/tt&gt;15&lt;tt&gt;
  406. &lt;/tt&gt;16&lt;tt&gt;
  407. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  408.  &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;
  409. &lt;/tt&gt;&lt;tt&gt;
  410. &lt;/tt&gt;&lt;span style=&quot;color:#808&quot;&gt;assets&lt;/span&gt;:&lt;tt&gt;
  411. &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;
  412. &lt;/tt&gt;&lt;tt&gt;
  413. &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;
  414. &lt;/tt&gt;  &lt;span style=&quot;color:#808&quot;&gt;enabled&lt;/span&gt;:&lt;tt&gt;
  415. &lt;/tt&gt;    - &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;tags&lt;/span&gt;&lt;tt&gt;
  416. &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;
  417. &lt;/tt&gt;  &lt;span style=&quot;color:#808&quot;&gt;permalinks&lt;/span&gt;:&lt;tt&gt;
  418. &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;
  419. &lt;/tt&gt;&lt;tt&gt;
  420. &lt;/tt&gt;&lt;span style=&quot;color:#808&quot;&gt;gems&lt;/span&gt;:&lt;tt&gt;
  421. &lt;/tt&gt;  - &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;jekyll-feed&lt;/span&gt;&lt;tt&gt;
  422. &lt;/tt&gt;  - &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;jekyll-assets&lt;/span&gt;&lt;tt&gt;
  423. &lt;/tt&gt;  - &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;jekyll-archives&lt;/span&gt;&lt;tt&gt;
  424. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  425. &lt;/tr&gt;&lt;/table&gt;
  426. &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;
  427.  &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;
  428. &lt;/tt&gt;2&lt;tt&gt;
  429. &lt;/tt&gt;3&lt;tt&gt;
  430. &lt;/tt&gt;4&lt;tt&gt;
  431. &lt;/tt&gt;5&lt;tt&gt;
  432. &lt;/tt&gt;6&lt;tt&gt;
  433. &lt;/tt&gt;7&lt;tt&gt;
  434. &lt;/tt&gt;8&lt;tt&gt;
  435. &lt;/tt&gt;9&lt;tt&gt;
  436. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  437. &lt;/tt&gt;11&lt;tt&gt;
  438. &lt;/tt&gt;12&lt;tt&gt;
  439. &lt;/tt&gt;13&lt;tt&gt;
  440. &lt;/tt&gt;14&lt;tt&gt;
  441. &lt;/tt&gt;15&lt;tt&gt;
  442. &lt;/tt&gt;16&lt;tt&gt;
  443. &lt;/tt&gt;17&lt;tt&gt;
  444. &lt;/tt&gt;18&lt;tt&gt;
  445. &lt;/tt&gt;19&lt;tt&gt;
  446. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  447. &lt;/tt&gt;21&lt;tt&gt;
  448. &lt;/tt&gt;22&lt;tt&gt;
  449. &lt;/tt&gt;23&lt;tt&gt;
  450. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  451.  &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;
  452. &lt;/tt&gt;{% assign last_month = nil %}&lt;tt&gt;
  453. &lt;/tt&gt;&amp;lt;ul&amp;gt;&lt;tt&gt;
  454. &lt;/tt&gt;{% for post in site.posts %}&lt;tt&gt;
  455. &lt;/tt&gt;  {% assign current_month = post.date | date: '%B %Y' %}&lt;tt&gt;
  456. &lt;/tt&gt;  {% if current_month != last_month %}&lt;tt&gt;
  457. &lt;/tt&gt;    &amp;lt;/ul&amp;gt;&lt;tt&gt;
  458. &lt;/tt&gt;    &amp;lt;h3&amp;gt;{{ current_month }}&amp;lt;/h3&amp;gt;&lt;tt&gt;
  459. &lt;/tt&gt;    &amp;lt;ul&amp;gt;&lt;tt&gt;
  460. &lt;/tt&gt;  {% endif %}&lt;tt&gt;
  461. &lt;/tt&gt;&lt;tt&gt;
  462. &lt;/tt&gt;  &amp;lt;li&amp;gt;&lt;tt&gt;
  463. &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;
  464. &lt;/tt&gt;&lt;tt&gt;
  465. &lt;/tt&gt;    {% if post.tags != empty %}&lt;tt&gt;
  466. &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;
  467. &lt;/tt&gt;    {% endif %}&lt;tt&gt;
  468. &lt;/tt&gt;  &amp;lt;/li&amp;gt;&lt;tt&gt;
  469. &lt;/tt&gt;&lt;tt&gt;
  470. &lt;/tt&gt;  {% assign last_month = current_month %}&lt;tt&gt;
  471. &lt;/tt&gt;{% endfor %}&lt;tt&gt;
  472. &lt;/tt&gt;&amp;lt;/ul&amp;gt;&lt;tt&gt;
  473. &lt;/tt&gt;{% include footer.html %}&lt;tt&gt;
  474. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  475. &lt;/tr&gt;&lt;/table&gt;
  476. &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><author><name></name></author><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><author><name></name></author><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;
  477.  &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;
  478. &lt;/tt&gt;2&lt;tt&gt;
  479. &lt;/tt&gt;3&lt;tt&gt;
  480. &lt;/tt&gt;4&lt;tt&gt;
  481. &lt;/tt&gt;5&lt;tt&gt;
  482. &lt;/tt&gt;6&lt;tt&gt;
  483. &lt;/tt&gt;7&lt;tt&gt;
  484. &lt;/tt&gt;8&lt;tt&gt;
  485. &lt;/tt&gt;9&lt;tt&gt;
  486. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  487. &lt;/tt&gt;11&lt;tt&gt;
  488. &lt;/tt&gt;12&lt;tt&gt;
  489. &lt;/tt&gt;13&lt;tt&gt;
  490. &lt;/tt&gt;14&lt;tt&gt;
  491. &lt;/tt&gt;15&lt;tt&gt;
  492. &lt;/tt&gt;16&lt;tt&gt;
  493. &lt;/tt&gt;17&lt;tt&gt;
  494. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  495.  &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;
  496. &lt;/tt&gt;[2014-08-17 15:29:10] INFO  WEBrick 1.3.1&lt;tt&gt;
  497. &lt;/tt&gt;[2014-08-17 15:29:10] INFO  ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0]&lt;tt&gt;
  498. &lt;/tt&gt;[2014-08-17 15:29:10] INFO  WEBrick::HTTPServer#start: pid=17304 port=8000&lt;tt&gt;
  499. &lt;/tt&gt;D, [2014-08-17T15:29:11.452223 #17304] DEBUG -- : hello from in the request&lt;tt&gt;
  500. &lt;/tt&gt;localhost - - [17/Aug/2014:15:29:11 PDT] &amp;quot;GET / HTTP/1.1&amp;quot; 200 13&lt;tt&gt;
  501. &lt;/tt&gt;- -&amp;gt; /&lt;tt&gt;
  502. &lt;/tt&gt;E, [2014-08-17T15:29:12.787505 #17304] ERROR -- : fail (RuntimeError)&lt;tt&gt;
  503. &lt;/tt&gt;server.rb:57:in `block in &amp;lt;main&amp;gt;'&lt;tt&gt;
  504. &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;
  505. &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;
  506. &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;
  507. &lt;/tt&gt;/Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service'&lt;tt&gt;
  508. &lt;/tt&gt;/Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run'&lt;tt&gt;
  509. &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;
  510. &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;
  511. &lt;/tt&gt;- -&amp;gt; /fail&lt;tt&gt;
  512. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  513. &lt;/tr&gt;&lt;/table&gt;
  514. &lt;p&gt;They looked like:&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  515.  &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;
  516. &lt;/tt&gt;2&lt;tt&gt;
  517. &lt;/tt&gt;3&lt;tt&gt;
  518. &lt;/tt&gt;4&lt;tt&gt;
  519. &lt;/tt&gt;5&lt;tt&gt;
  520. &lt;/tt&gt;6&lt;tt&gt;
  521. &lt;/tt&gt;7&lt;tt&gt;
  522. &lt;/tt&gt;8&lt;tt&gt;
  523. &lt;/tt&gt;9&lt;tt&gt;
  524. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  525. &lt;/tt&gt;11&lt;tt&gt;
  526. &lt;/tt&gt;12&lt;tt&gt;
  527. &lt;/tt&gt;13&lt;tt&gt;
  528. &lt;/tt&gt;14&lt;tt&gt;
  529. &lt;/tt&gt;15&lt;tt&gt;
  530. &lt;/tt&gt;16&lt;tt&gt;
  531. &lt;/tt&gt;17&lt;tt&gt;
  532. &lt;/tt&gt;18&lt;tt&gt;
  533. &lt;/tt&gt;19&lt;tt&gt;
  534. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  535. &lt;/tt&gt;21&lt;tt&gt;
  536. &lt;/tt&gt;22&lt;tt&gt;
  537. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  538.  &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;
  539. &lt;/tt&gt;&lt;tt&gt;
  540. &lt;/tt&gt;   ,~~.,''&amp;quot;'`'.~~.&lt;tt&gt;
  541. &lt;/tt&gt;  : {` .- _ -. '} ;&lt;tt&gt;
  542. &lt;/tt&gt;   `:   O(_)O   ;'&lt;tt&gt;
  543. &lt;/tt&gt;    ';  ._|_,  ;`   i am starting the server&lt;tt&gt;
  544. &lt;/tt&gt;     '`-.\_/,.'`&lt;tt&gt;
  545. &lt;/tt&gt;&lt;tt&gt;
  546. &lt;/tt&gt;INFO  [2014-08-17 22:28:13,186] webrick: WEBrick 1.3.1&lt;tt&gt;
  547. &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;
  548. &lt;/tt&gt;INFO  [2014-08-17 22:28:13,187] webrick: WEBrick::HTTPServer#start: pid=17253 port=8000&lt;tt&gt;
  549. &lt;/tt&gt;DEBUG [2014-08-17 22:28:14,738] app: hello from in the request&lt;tt&gt;
  550. &lt;/tt&gt;INFO  [2014-08-17 15:28:14,736] webrick: GET / 200&lt;tt&gt;
  551. &lt;/tt&gt;ERROR [2014-08-17 22:28:15,603] app: RuntimeError: fail&lt;tt&gt;
  552. &lt;/tt&gt;! server.rb:57:in `block in &amp;lt;main&amp;gt;'&lt;tt&gt;
  553. &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;
  554. &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;
  555. &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;
  556. &lt;/tt&gt;! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service'&lt;tt&gt;
  557. &lt;/tt&gt;! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run'&lt;tt&gt;
  558. &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;
  559. &lt;/tt&gt;INFO  [2014-08-17 15:28:15,602] webrick: GET /fail 500&lt;tt&gt;
  560. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  561. &lt;/tr&gt;&lt;/table&gt;
  562. &lt;p&gt;I thought so, hence:&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  563.  &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;
  564. &lt;/tt&gt;2&lt;tt&gt;
  565. &lt;/tt&gt;3&lt;tt&gt;
  566. &lt;/tt&gt;4&lt;tt&gt;
  567. &lt;/tt&gt;5&lt;tt&gt;
  568. &lt;/tt&gt;6&lt;tt&gt;
  569. &lt;/tt&gt;7&lt;tt&gt;
  570. &lt;/tt&gt;8&lt;tt&gt;
  571. &lt;/tt&gt;9&lt;tt&gt;
  572. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  573. &lt;/tt&gt;11&lt;tt&gt;
  574. &lt;/tt&gt;12&lt;tt&gt;
  575. &lt;/tt&gt;13&lt;tt&gt;
  576. &lt;/tt&gt;14&lt;tt&gt;
  577. &lt;/tt&gt;15&lt;tt&gt;
  578. &lt;/tt&gt;16&lt;tt&gt;
  579. &lt;/tt&gt;17&lt;tt&gt;
  580. &lt;/tt&gt;18&lt;tt&gt;
  581. &lt;/tt&gt;19&lt;tt&gt;
  582. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  583. &lt;/tt&gt;21&lt;tt&gt;
  584. &lt;/tt&gt;22&lt;tt&gt;
  585. &lt;/tt&gt;23&lt;tt&gt;
  586. &lt;/tt&gt;24&lt;tt&gt;
  587. &lt;/tt&gt;25&lt;tt&gt;
  588. &lt;/tt&gt;26&lt;tt&gt;
  589. &lt;/tt&gt;27&lt;tt&gt;
  590. &lt;/tt&gt;28&lt;tt&gt;
  591. &lt;/tt&gt;29&lt;tt&gt;
  592. &lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
  593. &lt;/tt&gt;31&lt;tt&gt;
  594. &lt;/tt&gt;32&lt;tt&gt;
  595. &lt;/tt&gt;33&lt;tt&gt;
  596. &lt;/tt&gt;34&lt;tt&gt;
  597. &lt;/tt&gt;35&lt;tt&gt;
  598. &lt;/tt&gt;36&lt;tt&gt;
  599. &lt;/tt&gt;37&lt;tt&gt;
  600. &lt;/tt&gt;38&lt;tt&gt;
  601. &lt;/tt&gt;39&lt;tt&gt;
  602. &lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
  603. &lt;/tt&gt;41&lt;tt&gt;
  604. &lt;/tt&gt;42&lt;tt&gt;
  605. &lt;/tt&gt;43&lt;tt&gt;
  606. &lt;/tt&gt;44&lt;tt&gt;
  607. &lt;/tt&gt;45&lt;tt&gt;
  608. &lt;/tt&gt;46&lt;tt&gt;
  609. &lt;/tt&gt;47&lt;tt&gt;
  610. &lt;/tt&gt;48&lt;tt&gt;
  611. &lt;/tt&gt;49&lt;tt&gt;
  612. &lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
  613. &lt;/tt&gt;51&lt;tt&gt;
  614. &lt;/tt&gt;52&lt;tt&gt;
  615. &lt;/tt&gt;53&lt;tt&gt;
  616. &lt;/tt&gt;54&lt;tt&gt;
  617. &lt;/tt&gt;55&lt;tt&gt;
  618. &lt;/tt&gt;56&lt;tt&gt;
  619. &lt;/tt&gt;57&lt;tt&gt;
  620. &lt;/tt&gt;58&lt;tt&gt;
  621. &lt;/tt&gt;59&lt;tt&gt;
  622. &lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
  623. &lt;/tt&gt;61&lt;tt&gt;
  624. &lt;/tt&gt;62&lt;tt&gt;
  625. &lt;/tt&gt;63&lt;tt&gt;
  626. &lt;/tt&gt;64&lt;tt&gt;
  627. &lt;/tt&gt;65&lt;tt&gt;
  628. &lt;/tt&gt;66&lt;tt&gt;
  629. &lt;/tt&gt;67&lt;tt&gt;
  630. &lt;/tt&gt;68&lt;tt&gt;
  631. &lt;/tt&gt;69&lt;tt&gt;
  632. &lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
  633. &lt;/tt&gt;71&lt;tt&gt;
  634. &lt;/tt&gt;72&lt;tt&gt;
  635. &lt;/tt&gt;73&lt;tt&gt;
  636. &lt;/tt&gt;74&lt;tt&gt;
  637. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  638.  &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;
  639. &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;
  640. &lt;/tt&gt;&lt;tt&gt;
  641. &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;
  642. &lt;/tt&gt;&lt;tt&gt;
  643. &lt;/tt&gt;   ,~~.,''&amp;quot;'`'.~~.&lt;tt&gt;
  644. &lt;/tt&gt;  : {` .- _ -. '} ;&lt;tt&gt;
  645. &lt;/tt&gt;   `:   O(_)O   ;'&lt;tt&gt;
  646. &lt;/tt&gt;    ';  ._|_,  ;`   i am starting the server&lt;tt&gt;
  647. &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;
  648. &lt;/tt&gt;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&lt;tt&gt;
  649. &lt;/tt&gt;BANNER&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
  650. &lt;/tt&gt;&lt;tt&gt;
  651. &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;
  652. &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;
  653. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;super&lt;/span&gt;(*args)&lt;tt&gt;
  654. &lt;/tt&gt;    &lt;span style=&quot;color:#33B&quot;&gt;@label&lt;/span&gt; = label&lt;tt&gt;
  655. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  656. &lt;/tt&gt;&lt;tt&gt;
  657. &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;
  658. &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;
  659. &lt;/tt&gt;      severity,&lt;tt&gt;
  660. &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;
  661. &lt;/tt&gt;      &lt;span style=&quot;color:#33B&quot;&gt;@label&lt;/span&gt;,&lt;tt&gt;
  662. &lt;/tt&gt;      msg2str(msg),&lt;tt&gt;
  663. &lt;/tt&gt;    ]&lt;tt&gt;
  664. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  665. &lt;/tt&gt;&lt;tt&gt;
  666. &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;
  667. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;case&lt;/span&gt; msg&lt;tt&gt;
  668. &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;
  669. &lt;/tt&gt;      msg&lt;tt&gt;
  670. &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;
  671. &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;
  672. &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;
  673. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;else&lt;/span&gt;&lt;tt&gt;
  674. &lt;/tt&gt;      msg.inspect&lt;tt&gt;
  675. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  676. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  677. &lt;/tt&gt;&lt;tt&gt;
  678. &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;
  679. &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;
  680. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  681. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  682. &lt;/tt&gt;&lt;tt&gt;
  683. &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;
  684. &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;
  685. &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;
  686. &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;
  687. &lt;/tt&gt;                },&lt;tt&gt;
  688. &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;
  689. &lt;/tt&gt;&lt;tt&gt;
  690. &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;
  691. &lt;/tt&gt;&lt;tt&gt;
  692. &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;
  693. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;begin&lt;/span&gt;&lt;tt&gt;
  694. &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;
  695. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;rescue&lt;/span&gt; =&amp;gt; e&lt;tt&gt;
  696. &lt;/tt&gt;    &lt;span style=&quot;color:#d70;font-weight:bold&quot;&gt;$logger&lt;/span&gt;.error(e)&lt;tt&gt;
  697. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  698. &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;
  699. &lt;/tt&gt;  res.status = &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;500&lt;/span&gt;&lt;tt&gt;
  700. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  701. &lt;/tt&gt;&lt;tt&gt;
  702. &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;
  703. &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;
  704. &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;
  705. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  706. &lt;/tt&gt;&lt;tt&gt;
  707. &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;
  708. &lt;/tt&gt;  server.shutdown&lt;tt&gt;
  709. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  710. &lt;/tt&gt;&lt;tt&gt;
  711. &lt;/tt&gt;server.start&lt;tt&gt;
  712. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  713. &lt;/tr&gt;&lt;/table&gt;</content><author><name></name></author><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: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 &amp;gt; ruby server.rb [2014-08-17 15:29:10] INFO WEBrick 1.3.1 [2014-08-17 15:29:10] INFO ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0] [2014-08-17 15:29:10] INFO WEBrick::HTTPServer#start: pid=17304 port=8000 D, [2014-08-17T15:29:11.452223 #17304] DEBUG -- : hello from in the request localhost - - [17/Aug/2014:15:29:11 PDT] &amp;quot;GET / HTTP/1.1&amp;quot; 200 13 - -&amp;gt; / E, [2014-08-17T15:29:12.787505 #17304] ERROR -- : fail (RuntimeError) server.rb:57:in `block in &amp;lt;main&amp;gt;' /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `call' /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `do_GET' /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/abstract.rb:106:in `service' /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service' /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run' /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/server.rb:295:in `block in start_thread' localhost - - [17/Aug/2014:15:29:12 PDT] &amp;quot;GET /fail HTTP/1.1&amp;quot; 500 6 - -&amp;gt; /fail They looked like: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 &amp;gt; ruby server.rb ,~~.,''&amp;quot;'`'.~~. : {` .- _ -. '} ; `: O(_)O ;' '; ._|_, ;` i am starting the server '`-.\_/,.'` INFO [2014-08-17 22:28:13,186] webrick: WEBrick 1.3.1 INFO [2014-08-17 22:28:13,186] webrick: ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0] INFO [2014-08-17 22:28:13,187] webrick: WEBrick::HTTPServer#start: pid=17253 port=8000 DEBUG [2014-08-17 22:28:14,738] app: hello from in the request INFO [2014-08-17 15:28:14,736] webrick: GET / 200 ERROR [2014-08-17 22:28:15,603] app: RuntimeError: fail ! server.rb:57:in `block in &amp;lt;main&amp;gt;' ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `call' ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/prochandler.rb:38:in `do_GET' ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpservlet/abstract.rb:106:in `service' ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service' ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run' ! /Users/xavier/.rubies/cruby-2.1.1/lib/ruby/2.1.0/webrick/server.rb:295:in `block in start_thread' INFO [2014-08-17 15:28:15,602] webrick: GET /fail 500 I thought so, hence: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 require 'webrick' require 'logger' puts &amp;lt;&amp;lt;-BANNER ,~~.,''&amp;quot;'`'.~~. : {` .- _ -. '} ; `: O(_)O ;' '; ._|_, ;` i am starting the server '`-.\\_/,.'` BANNER class DropwizardLogger &amp;lt; Logger def initialize(label, *args) super(*args) @label = label end def format_message(severity, timestamp, progname, msg) &amp;quot;%-5s [%s] %s: %s\n&amp;quot; % [ severity, timestamp.utc.strftime(&amp;quot;%Y-%m-%d %H:%M:%S,%3N&amp;quot;), @label, msg2str(msg), ] end def msg2str(msg) case msg when String msg when Exception (&amp;quot;%s: %s&amp;quot; % [msg.class, msg.message]) + (msg.backtrace ? msg.backtrace.map {|x| &amp;quot;\n! #{x}&amp;quot; }.join : &amp;quot;&amp;quot;) else msg.inspect end end def self.webrick_format(label) &amp;quot;INFO [%{%Y-%m-%d %H:%M:%S,%3N}t] #{label}: %m %U %s&amp;quot; end end server = WEBrick::HTTPServer.new \ :Port =&amp;gt; 8000, :Logger =&amp;gt; DropwizardLogger.new(&amp;quot;webrick&amp;quot;, $stdout).tap {|x| x.level = Logger::INFO }, :AccessLog =&amp;gt; [[$stdout, DropwizardLogger.webrick_format(&amp;quot;webrick&amp;quot;)]] $logger = DropwizardLogger.new(&amp;quot;app&amp;quot;, $stdout) server.mount_proc '/fail' do |req, res| begin raise 'fail' rescue =&amp;gt; e $logger.error(e) end res.body = &amp;quot;failed&amp;quot; res.status = 500 end server.mount_proc '/' do |req, res| $logger.debug(&amp;quot;hello from in the request&amp;quot;) res.body = 'Hello, world!' end trap 'INT' do server.shutdown end 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;
  714. &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;
  715. &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;
  716.  &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;
  717. &lt;/tt&gt;2&lt;tt&gt;
  718. &lt;/tt&gt;3&lt;tt&gt;
  719. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  720.  &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;
  721. &lt;/tt&gt;loglevel=DEBUG&lt;tt&gt;
  722. &lt;/tt&gt;consul=true&lt;tt&gt;
  723. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  724. &lt;/tr&gt;&lt;/table&gt;
  725. &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;
  726. &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;
  727.  &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;
  728. &lt;/tt&gt;2&lt;tt&gt;
  729. &lt;/tt&gt;3&lt;tt&gt;
  730. &lt;/tt&gt;4&lt;tt&gt;
  731. &lt;/tt&gt;5&lt;tt&gt;
  732. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  733.  &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;
  734. &lt;/tt&gt;&amp;gt; erg &amp;quot;allclusters()&amp;quot;&lt;tt&gt;
  735. &lt;/tt&gt;consul&lt;tt&gt;
  736. &lt;/tt&gt;&amp;gt; erg &amp;quot;%consul&amp;quot;&lt;tt&gt;
  737. &lt;/tt&gt;agent-one&lt;tt&gt;
  738. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  739. &lt;/tr&gt;&lt;/table&gt;
  740. &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;
  741.  &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;
  742. &lt;/tt&gt;2&lt;tt&gt;
  743. &lt;/tt&gt;3&lt;tt&gt;
  744. &lt;/tt&gt;4&lt;tt&gt;
  745. &lt;/tt&gt;5&lt;tt&gt;
  746. &lt;/tt&gt;6&lt;tt&gt;
  747. &lt;/tt&gt;7&lt;tt&gt;
  748. &lt;/tt&gt;8&lt;tt&gt;
  749. &lt;/tt&gt;9&lt;tt&gt;
  750. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  751. &lt;/tt&gt;11&lt;tt&gt;
  752. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  753.  &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;
  754. &lt;/tt&gt;&lt;tt&gt;
  755. &lt;/tt&gt;&amp;gt; erg &amp;quot;allclusters()&amp;quot;&lt;tt&gt;
  756. &lt;/tt&gt;consul,web&lt;tt&gt;
  757. &lt;/tt&gt;&amp;gt; erg &amp;quot;%web&amp;quot;&lt;tt&gt;
  758. &lt;/tt&gt;agent-two&lt;tt&gt;
  759. &lt;/tt&gt;&lt;tt&gt;
  760. &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;
  761. &lt;/tt&gt;&lt;tt&gt;
  762. &lt;/tt&gt;&amp;gt; erg &amp;quot;%web&amp;quot;&lt;tt&gt;
  763. &lt;/tt&gt;agent-one,agent-two&lt;tt&gt;
  764. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  765. &lt;/tr&gt;&lt;/table&gt;
  766. &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;
  767. &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><author><name></name></author><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. 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! 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: 1 2 3 [rangeserver] loglevel=DEBUG consul=true (It could run against any consul agent, but it&amp;#8217;s easier to demo on the master node.) Querying range, we already see a consul cluster, cluster. This is a default service containing the consul servers. 1 2 3 4 5 &amp;gt; export RANGE_HOST=172.20.20.10 &amp;gt; erg &amp;quot;allclusters()&amp;quot; consul &amp;gt; erg &amp;quot;%consul&amp;quot; agent-one Add a new service to the agents, and it shows up in range! 1 2 3 4 5 6 7 8 9 10 11 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 &amp;gt; erg &amp;quot;allclusters()&amp;quot; consul,web &amp;gt; erg &amp;quot;%web&amp;quot; agent-two 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 &amp;gt; erg &amp;quot;%web&amp;quot; agent-one,agent-two 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? 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><entry><title type="html">Bash script to keep a git clone synced with a remote</title><link href="http://localhost:4000/2014/04/26/bash-script-to-keep-a-git-clone-synced-with-a-remote/" rel="alternate" type="text/html" title="Bash script to keep a git clone synced with a remote" /><published>2014-04-26T18:20:00+00:00</published><updated>2014-04-26T18:20:00+00:00</updated><id>http://localhost:4000/2014/04/26/bash-script-to-keep-a-git-clone-synced-with-a-remote</id><content type="html" xml:base="http://localhost:4000/2014/04/26/bash-script-to-keep-a-git-clone-synced-with-a-remote/">&lt;p&gt;Use the following under a process manager (such as runit) to keep a local git clone in sync with a remote, when a push based solution isn&amp;#8217;t an option. Most other versions either neglect to verify remote is correct, or use &lt;code&gt;git pull&lt;/code&gt; which can fail if someone has been monkeying with the local version.&lt;/p&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  768.  &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;
  769. &lt;/tt&gt;2&lt;tt&gt;
  770. &lt;/tt&gt;3&lt;tt&gt;
  771. &lt;/tt&gt;4&lt;tt&gt;
  772. &lt;/tt&gt;5&lt;tt&gt;
  773. &lt;/tt&gt;6&lt;tt&gt;
  774. &lt;/tt&gt;7&lt;tt&gt;
  775. &lt;/tt&gt;8&lt;tt&gt;
  776. &lt;/tt&gt;9&lt;tt&gt;
  777. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  778. &lt;/tt&gt;11&lt;tt&gt;
  779. &lt;/tt&gt;12&lt;tt&gt;
  780. &lt;/tt&gt;13&lt;tt&gt;
  781. &lt;/tt&gt;14&lt;tt&gt;
  782. &lt;/tt&gt;15&lt;tt&gt;
  783. &lt;/tt&gt;16&lt;tt&gt;
  784. &lt;/tt&gt;17&lt;tt&gt;
  785. &lt;/tt&gt;18&lt;tt&gt;
  786. &lt;/tt&gt;19&lt;tt&gt;
  787. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  788. &lt;/tt&gt;21&lt;tt&gt;
  789. &lt;/tt&gt;22&lt;tt&gt;
  790. &lt;/tt&gt;23&lt;tt&gt;
  791. &lt;/tt&gt;24&lt;tt&gt;
  792. &lt;/tt&gt;25&lt;tt&gt;
  793. &lt;/tt&gt;26&lt;tt&gt;
  794. &lt;/tt&gt;27&lt;tt&gt;
  795. &lt;/tt&gt;28&lt;tt&gt;
  796. &lt;/tt&gt;29&lt;tt&gt;
  797. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  798.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;function update_git_repo() {&lt;tt&gt;
  799. &lt;/tt&gt;  GIT_DIR=$1&lt;tt&gt;
  800. &lt;/tt&gt;  GIT_REMOTE=$2&lt;tt&gt;
  801. &lt;/tt&gt;  GIT_BRANCH=${3:-master}&lt;tt&gt;
  802. &lt;/tt&gt;&lt;tt&gt;
  803. &lt;/tt&gt;  if [ ! -d $GIT_DIR ]; then&lt;tt&gt;
  804. &lt;/tt&gt;    CURRENT_SHA=&amp;quot;&amp;quot;&lt;tt&gt;
  805. &lt;/tt&gt;    git clone --depth 1 $GIT_REMOTE $GIT_DIR -b $GIT_BRANCH&lt;tt&gt;
  806. &lt;/tt&gt;  else&lt;tt&gt;
  807. &lt;/tt&gt;    CURRENT_REMOTE=$(cd $GIT_DIR &amp;amp;&amp;amp; git config --get remote.origin.url || true)&lt;tt&gt;
  808. &lt;/tt&gt;&lt;tt&gt;
  809. &lt;/tt&gt;    if [ &amp;quot;$GIT_REMOTE&amp;quot; == &amp;quot;$CURRENT_REMOTE&amp;quot; ]; then&lt;tt&gt;
  810. &lt;/tt&gt;      CURRENT_SHA=$(cat $GIT_DIR/.git/refs/heads/$GIT_BRANCH)&lt;tt&gt;
  811. &lt;/tt&gt;    else&lt;tt&gt;
  812. &lt;/tt&gt;      rm -Rf $GIT_DIR&lt;tt&gt;
  813. &lt;/tt&gt;      exit 0 # Process manager should restart this script&lt;tt&gt;
  814. &lt;/tt&gt;    fi&lt;tt&gt;
  815. &lt;/tt&gt;  fi&lt;tt&gt;
  816. &lt;/tt&gt;&lt;tt&gt;
  817. &lt;/tt&gt;  cd $GIT_DIR &amp;amp;&amp;amp; \&lt;tt&gt;
  818. &lt;/tt&gt;    git fetch &amp;amp;&amp;amp; \&lt;tt&gt;
  819. &lt;/tt&gt;    git reset --hard origin/$GIT_BRANCH&lt;tt&gt;
  820. &lt;/tt&gt;&lt;tt&gt;
  821. &lt;/tt&gt;  NEW_SHA=$(cat $GIT_DIR/.git/refs/heads/$GIT_BRANCH)&lt;tt&gt;
  822. &lt;/tt&gt;}&lt;tt&gt;
  823. &lt;/tt&gt;&lt;tt&gt;
  824. &lt;/tt&gt;update_git_repo &amp;quot;/tmp/myrepo&amp;quot; &amp;quot;git://example.com/my/repo.git&amp;quot;&lt;tt&gt;
  825. &lt;/tt&gt;&lt;tt&gt;
  826. &lt;/tt&gt;sleep 60 # No need for a tight loop&lt;tt&gt;
  827. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  828. &lt;/tr&gt;&lt;/table&gt;</content><author><name></name></author><category term="bash" /><category term="code" /><category term="git" /><summary type="html">Use the following under a process manager (such as runit) to keep a local git clone in sync with a remote, when a push based solution isn&amp;#8217;t an option. Most other versions either neglect to verify remote is correct, or use git pull which can fail if someone has been monkeying with the local version. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 function update_git_repo() { GIT_DIR=$1 GIT_REMOTE=$2 GIT_BRANCH=${3:-master} if [ ! -d $GIT_DIR ]; then CURRENT_SHA=&amp;quot;&amp;quot; git clone --depth 1 $GIT_REMOTE $GIT_DIR -b $GIT_BRANCH else CURRENT_REMOTE=$(cd $GIT_DIR &amp;amp;&amp;amp; git config --get remote.origin.url || true) if [ &amp;quot;$GIT_REMOTE&amp;quot; == &amp;quot;$CURRENT_REMOTE&amp;quot; ]; then CURRENT_SHA=$(cat $GIT_DIR/.git/refs/heads/$GIT_BRANCH) else rm -Rf $GIT_DIR exit 0 # Process manager should restart this script fi fi cd $GIT_DIR &amp;amp;&amp;amp; \ git fetch &amp;amp;&amp;amp; \ git reset --hard origin/$GIT_BRANCH NEW_SHA=$(cat $GIT_DIR/.git/refs/heads/$GIT_BRANCH) } update_git_repo &amp;quot;/tmp/myrepo&amp;quot; &amp;quot;git://example.com/my/repo.git&amp;quot; sleep 60 # No need for a tight loop</summary></entry><entry><title type="html">Ruby progress bar, no gems</title><link href="http://localhost:4000/2014/03/29/ruby-progress-bar-no-gems/" rel="alternate" type="text/html" title="Ruby progress bar, no gems" /><published>2014-03-29T22:17:00+00:00</published><updated>2014-03-29T22:17:00+00:00</updated><id>http://localhost:4000/2014/03/29/ruby-progress-bar-no-gems</id><content type="html" xml:base="http://localhost:4000/2014/03/29/ruby-progress-bar-no-gems/">&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  829.  &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;
  830. &lt;/tt&gt;2&lt;tt&gt;
  831. &lt;/tt&gt;3&lt;tt&gt;
  832. &lt;/tt&gt;4&lt;tt&gt;
  833. &lt;/tt&gt;5&lt;tt&gt;
  834. &lt;/tt&gt;6&lt;tt&gt;
  835. &lt;/tt&gt;7&lt;tt&gt;
  836. &lt;/tt&gt;8&lt;tt&gt;
  837. &lt;/tt&gt;9&lt;tt&gt;
  838. &lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
  839. &lt;/tt&gt;11&lt;tt&gt;
  840. &lt;/tt&gt;12&lt;tt&gt;
  841. &lt;/tt&gt;13&lt;tt&gt;
  842. &lt;/tt&gt;14&lt;tt&gt;
  843. &lt;/tt&gt;15&lt;tt&gt;
  844. &lt;/tt&gt;16&lt;tt&gt;
  845. &lt;/tt&gt;17&lt;tt&gt;
  846. &lt;/tt&gt;18&lt;tt&gt;
  847. &lt;/tt&gt;19&lt;tt&gt;
  848. &lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
  849. &lt;/tt&gt;21&lt;tt&gt;
  850. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  851.  &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:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;import&lt;/span&gt;(filename, out = &lt;span style=&quot;color:#d70;font-weight:bold&quot;&gt;$stdout&lt;/span&gt;, &amp;amp;block)&lt;tt&gt;
  852. &lt;/tt&gt;  &lt;span style=&quot;color:#888&quot;&gt;# Yes, there are gems that do progress bars.&lt;/span&gt;&lt;tt&gt;
  853. &lt;/tt&gt;  &lt;span style=&quot;color:#888&quot;&gt;# No, I'm not about to add another dependency for something this simple.&lt;/span&gt;&lt;tt&gt;
  854. &lt;/tt&gt;  width     = &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;50&lt;/span&gt;&lt;tt&gt;
  855. &lt;/tt&gt;  processed = &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;0&lt;/span&gt;&lt;tt&gt;
  856. &lt;/tt&gt;  printed   = &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;0&lt;/span&gt;&lt;tt&gt;
  857. &lt;/tt&gt;  total     = &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;File&lt;/span&gt;.read(filename).lines.length.to_f&lt;tt&gt;
  858. &lt;/tt&gt;  label     = &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;File&lt;/span&gt;.basename(filename, &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;.csv&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
  859. &lt;/tt&gt;&lt;tt&gt;
  860. &lt;/tt&gt;  out.print &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;%11s: |&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; % label&lt;tt&gt;
  861. &lt;/tt&gt;&lt;tt&gt;
  862. &lt;/tt&gt;  &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;CSV&lt;/span&gt;.foreach(filename, &lt;span style=&quot;color:#808&quot;&gt;headers&lt;/span&gt;: &lt;span style=&quot;color:#038;font-weight:bold&quot;&gt;true&lt;/span&gt;) &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;do&lt;/span&gt; |row|&lt;tt&gt;
  863. &lt;/tt&gt;    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;yield&lt;/span&gt; row&lt;tt&gt;
  864. &lt;/tt&gt;&lt;tt&gt;
  865. &lt;/tt&gt;    processed += &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;1&lt;/span&gt;&lt;tt&gt;
  866. &lt;/tt&gt;    wanted = (processed / total * width).to_i&lt;tt&gt;
  867. &lt;/tt&gt;    out.print &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; * (wanted - printed)&lt;tt&gt;
  868. &lt;/tt&gt;    printed = wanted&lt;tt&gt;
  869. &lt;/tt&gt;  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  870. &lt;/tt&gt;  out.puts &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;
  871. &lt;/tt&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
  872. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  873. &lt;/tr&gt;&lt;/table&gt;
  874. &lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  875.  &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;
  876. &lt;/tt&gt;2&lt;tt&gt;
  877. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  878.  &lt;td class=&quot;code&quot;&gt;&lt;pre ondblclick=&quot;with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }&quot;&gt;     file_1: |--------------------------------------------------|&lt;tt&gt;
  879. &lt;/tt&gt;     file_2: |--------------------------------------------------|&lt;tt&gt;
  880. &lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  881. &lt;/tr&gt;&lt;/table&gt;</content><author><name></name></author><category term="code" /><category term="ruby" /><summary type="html">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 def import(filename, out = $stdout, &amp;amp;block) # Yes, there are gems that do progress bars. # No, I'm not about to add another dependency for something this simple. width = 50 processed = 0 printed = 0 total = File.read(filename).lines.length.to_f label = File.basename(filename, '.csv') out.print &amp;quot;%11s: |&amp;quot; % label CSV.foreach(filename, headers: true) do |row| yield row processed += 1 wanted = (processed / total * width).to_i out.print &amp;quot;-&amp;quot; * (wanted - printed) printed = wanted end out.puts &amp;quot;|&amp;quot; end 1 2 file_1: |--------------------------------------------------| file_2: |--------------------------------------------------|</summary></entry></feed>
Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda