<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Gleb's Notes</title>
  <subtitle>A software engineering blog</subtitle>
  <id>http://blog.glebm.com/</id>
  <link href="http://blog.glebm.com/"/>
  <link href="http://blog.glebm.com/feed.xml" rel="self"/>
  <updated>2018-04-02T15:16:00+01:00</updated>
  <author>
    <name>Gleb Mazovetskiy</name>
  </author>
  <entry>
    <title>Configuring Ubuntu 17.10 to behave like Unity</title>
    <link rel="alternate" href="http://blog.glebm.com/2018/04/02/configuring-ubuntu-17-10-to-behave-like-unity.html"/>
    <id>http://blog.glebm.com//2018/04/02/configuring-ubuntu-17-10-to-behave-like-unity.html</id>
    <published>2018-04-02T15:16:00+01:00</published>
    <updated>2018-04-02T15:16:00+01:00</updated>
    <author>
      <name>Gleb Mazovetskiy</name>
    </author>
    <content type="html">&lt;p&gt;I've recently upgraded from Ubuntu 16.04 to Ubuntu 17.10. The new Ubuntu uses
Gnome desktop by default instead of Unity. Gnome is quite different but luckily
can be customized to match Unity's behaviour very closely. Here is how.&lt;/p&gt;

&lt;p&gt;&lt;a href="/images/2018-04-02-configuring-ubuntu-17-10-to-behave-like-unity/ubuntu17-like-unity.png"&gt;
  &lt;img src="http://blog.glebm.com/images/2018-04-02-configuring-ubuntu-17-10-to-behave-like-unity/ubuntu17-like-unity.png" class="img-fluid" width="1298" height="365" alt="Ubuntu17 like unity" /&gt;
&lt;/a&gt;&lt;/p&gt;

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

&lt;h2 id="goals"&gt;Goals&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Show the current time in the top bar on the right.&lt;/li&gt;
  &lt;li&gt;Show legacy app indicators (tray icons) on the right.&lt;/li&gt;
  &lt;li&gt;Merge the window title bar with the top bar when maximized.&lt;/li&gt;
  &lt;li&gt;Hide the top-left &lt;em&gt;Activities&lt;/em&gt; button.&lt;/li&gt;
  &lt;li&gt;Allow quick device selection via the top bar Sound button.&lt;/li&gt;
  &lt;li&gt;Place window buttons on the left.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="setup-guide"&gt;Setup guide&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;First, install &lt;em&gt;Tweaks&lt;/em&gt;, a GNOME configuration UI that has options that are not
yet available in the default Settings app:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt install gnome-tweak-tool
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;Then install &lt;code&gt;x11-utils&lt;/code&gt;, a package often required by Gnome extensions:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt install x11-utils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;You can install Gnome extensions from &lt;a href="https://extensions.gnome.org"&gt;https://extensions.gnome.org&lt;/a&gt; and
manage and configure the installed extensions in &lt;em&gt;Tweaks -&amp;gt; Extensions&lt;/em&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install the &lt;a href="https://extensions.gnome.org/extension/1287"&gt;Unite extension&lt;/a&gt; for goals 1-4.&lt;/p&gt;

    &lt;p&gt;Alternatively, e.g. if Unite doesn't work for you or you'd like more
customization, install the following plugins: &lt;a href="https://extensions.gnome.org/extension/1267"&gt;No title bar&lt;/a&gt;, &lt;a href="https://extensions.gnome.org/extension/744"&gt;Hide
activities button&lt;/a&gt;, and &lt;a href="https://extensions.gnome.org/extension/2"&gt;Frippery Move Clock&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install the &lt;a href="https://extensions.gnome.org/extension/906"&gt;Sound Input &amp;amp; Output Device Chooser&lt;/a&gt; extension to add sound
device selection to the top bar sound menu.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;To place window buttons on the left, adjust &lt;em&gt;Tweaks -&amp;gt; Windows -&amp;gt; Titlebar
Buttons -&amp;gt; Placement&lt;/em&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="other-tips"&gt;Other tips&lt;/h2&gt;

&lt;p&gt;If you use Google Chrome, enable "Use system title bar and borders" in
&lt;code&gt;chrome://settings&lt;/code&gt; for consistency with other apps.&lt;/p&gt;

&lt;p&gt;You can disable animations from &lt;em&gt;Tweaks -&amp;gt; Appearance -&amp;gt; Animations&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can change the default monospace font from &lt;em&gt;Tweaks -&amp;gt; Fonts&lt;/em&gt;. I prefer &lt;em&gt;Hack
Regular&lt;/em&gt; at 11pt:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt install fonts-hack-ttf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To have your multi-monitor setup work on the login screen, run:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;cp ~/.config/monitors.xml /var/lib/gdm3/.config/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Keyboard shortcuts can be configured in &lt;em&gt;Settings -&amp;gt; Devices -&amp;gt; Keyboard&lt;/em&gt;. I
find it useful to remove &lt;em&gt;Maximise window&lt;/em&gt; and instead set &lt;em&gt;Toggle maximisation
state&lt;/em&gt; to &lt;kbd&gt;Super + Up&lt;/kbd&gt;.&lt;/p&gt;

</content>
  </entry>
  <entry>
    <title>Database-agnostic case-insensitive equality, full text search</title>
    <link rel="alternate" href="http://blog.glebm.com/2016/03/31/db-text-search.html"/>
    <id>http://blog.glebm.com//2016/03/31/db-text-search.html</id>
    <published>2016-03-31T03:00:00+01:00</published>
    <updated>2016-03-31T03:00:00+01:00</updated>
    <author>
      <name>Gleb Mazovetskiy</name>
    </author>
    <content type="html">&lt;p&gt;Different relational databases treat text search very differently.
The new &lt;a href="https://github.com/thredded/db_text_search"&gt;DbTextSearch gem&lt;/a&gt; provides a unified interface on top of ActiveRecord for SQLite, MySQL, and
PostgreSQL to do:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Case-insensitive string-in-set querying, and CI index creation.&lt;/li&gt;
  &lt;li&gt;Basic full-text search for a list of terms, and FTS index creation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/thredded/db_text_search"&gt;DbTextSearch&lt;/a&gt; does all the heavy lifting under the hood, hiding the complexity of handling each
database differently away, which is great for gem authors, when migrating an application from one database to another,
or writing code that must support multiple databases.&lt;/p&gt;

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

&lt;p&gt;Here is how &lt;a href="https://github.com/thredded/db_text_search"&gt;db_text_search&lt;/a&gt; handles different types of columns in different databases for case-insensitive comparisons:&lt;/p&gt;
&lt;div class="table-responsive"&gt;
&lt;table style="font-size: 16px; border: 0" class="table table-striped table-sm table-center-cells table-bordered"&gt;
&lt;caption&gt;&lt;a href="https://github.com/thredded/db_text_search"&gt;DbTextSearch&lt;/a&gt; case-insensitive string matching methods&lt;/caption&gt;
&lt;thead&gt;
  &lt;tr&gt;&lt;th style="vertical-align: bottom" rowspan="2"&gt;Column type&lt;/th&gt;&lt;th colspan="2"&gt;SQLite&lt;/th&gt;&lt;th colspan="2"&gt;MySQL&lt;/th&gt;&lt;th colspan="2"&gt;PostgreSQL&lt;/th&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;th&gt;Detected types&lt;/th&gt;&lt;th&gt;Search / index&lt;/th&gt;&lt;th&gt;Detected types&lt;/th&gt;&lt;th&gt;Search / index&lt;/th&gt;&lt;th&gt;Detected types&lt;/th&gt;&lt;th&gt;Search / index&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody style="text-align: center"&gt;
  &lt;tr&gt;&lt;th&gt;Case-insensitive&lt;/th&gt;
      &lt;td rowspan="2"&gt;always treated as case-sensitive&lt;/td&gt; &lt;td rowspan="2"&gt;&lt;code&gt;COLLATE&amp;nbsp;NOCASE&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;i&gt;default&lt;/i&gt;&lt;/td&gt; &lt;td&gt;&lt;i&gt;default&lt;/i&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;CITEXT&lt;/code&gt;&lt;/td&gt; &lt;td&gt;&lt;i&gt;default&lt;/i&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;&lt;th&gt;Case-sensitive&lt;/th&gt;
    &lt;td&gt;non-&lt;code&gt;ci&lt;/code&gt; collations&lt;/td&gt; &lt;td&gt;&lt;code&gt;LOWER&lt;/code&gt;&lt;br /&gt;&lt;b&gt;no index&lt;/b&gt;&lt;/td&gt;
    &lt;td&gt;&lt;i&gt;default&lt;/i&gt;&lt;/td&gt; &lt;td&gt;&lt;code&gt;LOWER&lt;/code&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Full-text search is even more gnarly. Great that you don't have to worry about that if you use this gem!
Check it out and learn more on &lt;a href="https://github.com/thredded/db_text_search"&gt;github.com/thredded/db_text_search&lt;/a&gt;.&lt;/p&gt;

</content>
  </entry>
  <entry>
    <title>Internationalization made easier with static analysis</title>
    <link rel="alternate" href="http://blog.glebm.com/2014/02/27/i18n-made-easier-with-static-analysis.html"/>
    <id>http://blog.glebm.com//2014/02/27/i18n-made-easier-with-static-analysis.html</id>
    <published>2014-02-27T08:41:00+00:00</published>
    <updated>2014-02-27T08:41:00+00:00</updated>
    <author>
      <name>Gleb Mazovetskiy</name>
    </author>
    <content type="html">&lt;p&gt;&lt;a href="https://github.com/glebm/i18n-tasks" title="glebm/i18n-tasks on Github"&gt;i18n-tasks&lt;/a&gt; finds and manages missing and unused translations in your application.
The default approach to locale data management with gems such as &lt;a href="https://github.com/svenfuchs/i18n" title="svenfuchs/i18n on Github"&gt;i18n&lt;/a&gt; is flawed.
If you use a key that does not exist, this will only blow up at runtime. Keys left over from removed code accumulate
in the resource files and introduce unnecessary overhead on the translators. Translation files can quickly turn to disarray.&lt;/p&gt;

&lt;p&gt;i18n-tasks improves this by using static analysis. It scans calls such as &lt;code&gt;I18n.t('some.key')&lt;/code&gt; and provides reports on key usage, missing, and unused keys.
It can also can pre-fill missing keys, including from Google Translate, and it can remove unused keys as well.&lt;/p&gt;

&lt;p&gt;i18n-tasks can be used with any project using &lt;a href="https://github.com/svenfuchs/i18n" title="svenfuchs/i18n on Github"&gt;i18n&lt;/a&gt; (default in Rails).&lt;/p&gt;

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

&lt;p&gt;It can make translation easier in many ways:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ i18n-tasks
Usage: i18n-tasks &amp;lt;command&amp;gt; [options]
    -v, --version      Print the version
    -h, --help         Display this help message.

Available commands:

  missing             show missing translations
  unused              show unused translations
  translate-missing   translate missing keys with Google Translate
  add-missing         add missing keys to the locales
  find                show where the keys are used in the code
  normalize           normalize translation data: sort and move to the right files
  remove-unused       remove unused keys
  config              display i18n-tasks configuration
  xlsx-report         save missing and unused translations to an Excel file

See `&amp;lt;command&amp;gt; --help` for more information on a specific command.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are lots of settings and you can use this on non-ruby codebases.&lt;/p&gt;

&lt;p&gt;Reports come rendered in colourful full-resolution &lt;a href="https://github.com/visionmedia/terminal-table"&gt;terminal tables&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/glebm/i18n-tasks" target="_blank"&gt;&lt;img width="539" height="331" src="https://i.imgur.com/XZBd8l7.png" style="max-width:100%;" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ i18n-tasks usages 'activities.*'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/glebm/i18n-tasks" target="_blank"&gt;&lt;img width="655" height="193" src="https://i.imgur.com/VxBrSfY.png" alt="i18n-screenshot" title="i18n-tasks find output screenshot" style="max-width:100%;" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id="see-also"&gt;See also&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://github.com/glebm/i18n-tasks"&gt;i18n-tasks on GitHub&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=7312390"&gt;HackerNews thread&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  <entry>
    <title>Save Redis memory with large list packing</title>
    <link rel="alternate" href="http://blog.glebm.com/2013/08/31/redis-compressed-lists.html"/>
    <id>http://blog.glebm.com//2013/08/31/redis-compressed-lists.html</id>
    <published>2013-08-31T17:54:00+01:00</published>
    <updated>2013-08-31T17:54:00+01:00</updated>
    <author>
      <name>Gleb Mazovetskiy</name>
    </author>
    <content type="html">&lt;p&gt;Redis is great for storing certain types of data that do not do well in a relational database.
It is great for storing caches and statistics too.
However, the storage capacity of redis is capped by RAM size, so care is required when storing large amounts of data in it.&lt;/p&gt;

&lt;p&gt;I will show you a trick to reduce memory usage and improve the speed of the redis &lt;em&gt;list&lt;/em&gt; type for storing series-type data (e.g. time series).
Redis &lt;a href="https://github.com/antirez/redis/blob/unstable/src/ziplist.c"&gt;packs&lt;/a&gt; small lists of ints, reducing their memory usage by 10-40%.
The exact list size threshold at which redis stops compressing is defined by the &lt;code&gt;list-max-ziplist-entries&lt;/code&gt; setting and defaults to 512.&lt;/p&gt;

&lt;p&gt;Here is the trick: we will transparently partition a list into many small lists of &lt;code&gt;list-max-ziplist-entries&lt;/code&gt; size.
By storing lists under the threshold, we take advantage of redis' ability to pack them.&lt;/p&gt;

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

&lt;p&gt;Here is a memory usage benchmark with random int values between 0 and 10:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.glebm.com/images/2013-08-31-redis-compressed-lists/bm-512.png" class="img-fluid" width="1200" height="600" alt="Bm 512" /&gt;&lt;/p&gt;

&lt;p&gt;To benchmark access speed let's try some random accesses on a large list:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bm_speed: 3,000,000 keys, 100 random range reads
                           user     system      total        real
regular                0.380000   0.040000   0.420000 (  0.686875)
partitioned            0.390000   0.060000   0.450000 (  0.482544)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Even despite Ruby overhead we still have both wall-clock time and memory savings.
A regular redis list is a linked list, so getting ranges out of it is slow.
However, when we use this technique the list is partitioned, and it only takes &lt;code&gt;O(1)&lt;/code&gt; to get to the correct partition.
As you increase &lt;code&gt;list-max-ziplist-entries&lt;/code&gt;, memory savings increase and range queries get slower.&lt;/p&gt;

&lt;p&gt;I published a &lt;a href="https://github.com/glebm/redis_stats/blob/master/lib/redis_stats/int_series.rb"&gt;Ruby implementation&lt;/a&gt; of this approach for int and time series.&lt;/p&gt;

&lt;p&gt;Are you doing something similar? I am curious to hear other approaches.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks &lt;a href="https://twitter.com/ddtrejo"&gt;@ddtrejo&lt;/a&gt; for your edits and suggestions!&lt;/em&gt;&lt;/p&gt;

&lt;h4 id="notes"&gt;Notes&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Packing efficiency depends on the data. Benchmark with your real data.&lt;/li&gt;
  &lt;li&gt;You can implement a similar trick for hashes and sets, redis will compress them based on the respective &lt;code&gt;-ziplist-entries&lt;/code&gt; values.&lt;/li&gt;
  &lt;li&gt;Tested on redis 2.6.14, installed via homebrew on OS X 10.8.3.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id="see-also"&gt;See also&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=6307769"&gt;Discussion on Hacker News&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Instagram dev blog post on &lt;a href="http://instagram-engineering.tumblr.com/post/12202313862/storing-hundreds-of-millions-of-simple-key-value-pairs"&gt;storing key-value pairs using partitioned hashes&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.manning.com/carlson/"&gt;Redis in Action&lt;/a&gt; book by &lt;a href="https://twitter.com/dr_josiah"&gt;@dr_josiah&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  <entry>
    <title>Inline CSS web fonts</title>
    <link rel="alternate" href="http://blog.glebm.com/2013/08/28/inline-css-fonts.html"/>
    <id>http://blog.glebm.com//2013/08/28/inline-css-fonts.html</id>
    <published>2013-08-28T17:34:00+01:00</published>
    <updated>2013-08-28T17:34:00+01:00</updated>
    <author>
      <name>Gleb Mazovetskiy</name>
    </author>
    <content type="html">&lt;p&gt;If you serve web fonts via URL, the browser makes a separate request for every web font.&lt;/p&gt;

&lt;p&gt;This is what the timeline looks like for a URL referenced font:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.glebm.com/images/2013-08-28-inline-css-fonts/tl-body.png" class="img-fluid" width="469" height="281" alt="Tl body" /&gt;&lt;/p&gt;

&lt;h4 class="text-center"&gt;
  &lt;span style="color: rgba(0, 0, 255, 0.67)"&gt;Ready&lt;/span&gt; &lt;span style="color: rgba(255, 0, 0, 0.78)"&gt;Load&lt;/span&gt;
&lt;/h4&gt;

&lt;p&gt;Fonts included from stylesheets cause extra requests that only starts once the DOM has loaded.
This causes a delay and flash of missing text or a font change flash while the fonts are loading.&lt;/p&gt;

&lt;p&gt;However, you can avoid extra requests &lt;em&gt;and&lt;/em&gt; rendering issues if you inline the fonts as data-uris.&lt;/p&gt;

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

&lt;p&gt;Inline web fonts with this script:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# download inliner and mark it as executable&lt;/span&gt;
curl https://gist.githubusercontent.com/glebm/6360088/raw &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; inline-fonts.rb&lt;span class="p"&gt;;&lt;/span&gt; chmod +x inline-fonts.rb
&lt;span class="c"&gt;# provide URL or path to convert&lt;/span&gt;
./inline-fonts.rb &lt;span class="s1"&gt;'https://fonts.googleapis.com/css?family=Arimo:400'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/glebm/6360088"&gt;The script&lt;/a&gt; outputs CSS with all the &lt;code&gt;url&lt;/code&gt; values inlined in data-uris, &lt;code&gt;woff&lt;/code&gt; format.
You can now deliver the fonts and CSS together in 1 request and the rendering is perfect,
no more &lt;a href="http://en.wikipedia.org/wiki/Flash_of_unstyled_content"&gt;&lt;def title="Flash of Unstyled Content"&gt;FOUC&lt;/def&gt;&lt;/a&gt; or font change.&lt;/p&gt;

&lt;h3 id="there-be-dragons"&gt;There be dragons&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;base64 encoding causes a +33% file size increase, but gzip mitigates this&lt;/li&gt;
  &lt;li&gt;when there are more fonts files at some point it is faster to download them in parallel, depending on the font sizes and latency / bandwidth of the audience.&lt;/li&gt;
  &lt;li&gt;public CDN files may already be in browser cache (e.g. the most popular Google Web Fonts)&lt;/li&gt;
  &lt;li&gt;the most common format woff is &lt;a href="http://caniuse.com/woff"&gt;supported&lt;/a&gt; everywhere but IE 8, stock Anroid Browser,
and Chrome on Windows, which has a &lt;a href="https://code.google.com/p/chromium/issues/detail?id=137692"&gt;general rendering issue&lt;/a&gt; with some fonts, and base64 &lt;a href="http://www.mobify.com/blog/data-uris-are-slow-on-mobile/"&gt;is slow on Android 2 and iOS 5&lt;/a&gt;.
You will have to serve other formats to these browsers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most individual font sizes are in 10 - 20 KB range; if you only use a few font files this could easily cut down initial load times by 5-20%.
Measure with any client-side monitoring tool to find out (it is best if your tool shows the distribution, and not just the average).&lt;/p&gt;

&lt;p&gt;This is what the timeline looks like once the fonts are inlined:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.glebm.com/images/2013-08-28-inline-css-fonts/tl-inline.png" class="img-fluid" width="642" height="453" alt="Tl inline" /&gt;&lt;/p&gt;

&lt;p&gt;When inlined, all the fonts are finished downloading before DOMContentReady fires.&lt;/p&gt;

&lt;p&gt;Alternatively, you could try using &lt;a href="https://developers.google.com/speed/pagespeed/module"&gt;Google Page Speed Module&lt;/a&gt;, which may intellegently apply this and other optimizations, but has it's own drawbacks.
&lt;a href="http://en.wikipedia.org/wiki/SPDY"&gt;SPDY&lt;/a&gt; should already be on for both timelines.&lt;/p&gt;

&lt;h4 id="see-also"&gt;See also&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=6304999"&gt;Discussion on Hacker News&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  <entry>
    <title>Store screenshots of your web app in Git</title>
    <link rel="alternate" href="http://blog.glebm.com/2013/08/23/screenshots-in-git.html"/>
    <id>http://blog.glebm.com//2013/08/23/screenshots-in-git.html</id>
    <published>2013-08-23T17:22:00+01:00</published>
    <updated>2013-08-23T17:22:00+01:00</updated>
    <author>
      <name>Gleb Mazovetskiy</name>
    </author>
    <content type="html">&lt;iframe style="max-width:100%" width="600" height="340" src="//www.youtube.com/embed/VMhdKZDxFjg" frameborder="0" allowfullscreen=""&gt;&lt;/iframe&gt;

&lt;p&gt;Have you ever had a change break your site? Even when the tests pass?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Testing functionality is hard&lt;/li&gt;
  &lt;li&gt;Testing UI is even harder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What if every time you commit, you got a visual diff of every web page that changed?
It is surprisingly easy to do.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.glebm.com/images/2013-08-23-screenshots-in-git/gh-img-diff-1.png" class="img-fluid" width="828" height="296" alt="Gh img diff 1" /&gt;&lt;/p&gt;

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

&lt;h3 id="how"&gt;How?&lt;/h3&gt;
&lt;p&gt;All we need is a headless browser and a testing environment.&lt;/p&gt;

&lt;p&gt;For Rails you can use poltergeist + rspec and &lt;a href="https://github.com/glebm/rails_email_preview/blob/master/spec/support/save_screenshots.rb"&gt;just&lt;/a&gt; do &lt;a href="https://github.com/glebm/rails_email_preview/blob/master/spec/features/take_screenshots_spec.rb"&gt;this&lt;/a&gt; like in the tests for my &lt;a href="https://github.com/glebm/rails_email_preview"&gt;Rails Email Preview&lt;/a&gt; gem. You then simply list the shots you want:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'Take screenshots'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;driver: :poltergeist&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'home page'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;
    &lt;span class="n"&gt;screenshot!&lt;/span&gt; &lt;span class="s1"&gt;'home'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'user account page'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;sign_in&lt;/span&gt; &lt;span class="no"&gt;Fabricate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;my_account_url&lt;/span&gt;
    &lt;span class="n"&gt;screenshot!&lt;/span&gt; &lt;span class="s1"&gt;'my-account'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code will simply place screenshots into &lt;code&gt;spec/screenshots&lt;/code&gt;  each time the test suite is run.&lt;/p&gt;

&lt;p&gt;Once you add &lt;code&gt;spec/screenshots&lt;/code&gt; to git, things get interesting.&lt;/p&gt;

&lt;h3 id="perks-unlocked"&gt;Perks unlocked&lt;/h3&gt;
&lt;p&gt;With your screenshots under version control, you will&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Always know when you introduce a change that changes the display&lt;/li&gt;
  &lt;li&gt;See which commits changed screens in your app&lt;/li&gt;
  &lt;li&gt;Instantly see what your app looked like at any point in time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You must use &lt;code&gt;git submodule add {separate repo URL} spec/screenshots&lt;/code&gt; to keep screenshots in a separate repo, as it will get large.
You can also script rewriting images out of older commits via &lt;code&gt;git filter-branch&lt;/code&gt; if repo grows too large.&lt;/p&gt;

&lt;p&gt;Below is an image diff as &lt;a href="https://github.com/glebm/rails_email_preview/commit/b6b003bf3a49ecf36d51ecf39dcd57e42e259dad?&amp;amp;diff-1=1-82#L14R3"&gt;rendered by Github&lt;/a&gt;. This is &lt;em&gt;visual version history&lt;/em&gt; and your private &lt;em&gt;git wayback machine&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/glebm/rails_email_preview/commit/b6b003bf3a49ecf36d51ecf39dcd57e42e259dad?&amp;amp;diff-1=1-82#L14R3"&gt;&lt;img src="http://blog.glebm.com/images/2013-08-23-screenshots-in-git/gh-img-diff-2.png" class="img-fluid" width="828" height="432" alt="Gh img diff 2" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope this post has helped you. Please let me know if you already do this, as I'm curious to hear other approaches.&lt;/p&gt;

&lt;p&gt;– &lt;a href="https://twitter.com/glebm"&gt;@glebm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks &lt;a href="https://twitter.com/ddtrejo"&gt;@ddtrejo&lt;/a&gt; for your edits and suggestions!&lt;/em&gt;&lt;/p&gt;

&lt;h4 id="see-also"&gt;See also&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=6266490"&gt;Discussion on Hacker News&lt;/a&gt; - some nice ideas around this approach.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://github.com/facebook/huxley/"&gt;Huxley&lt;/a&gt; - implementation of screenshot control in Selenium and written in Python. &lt;em&gt;Thanks &lt;a href="https://github.com/petehunt"&gt;@petehunt&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
</feed>
