<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>chatche's</title>
  <id>http://chatch.es/</id>
  <updated>2010-07-22</updated>
  <author>
    <name>philip</name>
  </author>
  <entry>
    <title>Quick lists using localStorage and contentEditable</title>
    <link rel="alternate" href="http://chatch.es/blog/2010/09/20/quick-lists-using-localstorage-and-contenteditable/"/>
    <id>http://chatch.es/blog/2010/09/20/quick-lists-using-localstorage-and-contenteditable/</id>
    <published>2010-09-20</published>
    <updated>2010-09-20</updated>
    <author>
      <name>philip</name>
    </author>
    <summary type="html">&lt;p&gt;
    &lt;img alt="screenshot example of quick lists" class="right" src="http://chatch.es/images/quick-lists-example.png"&gt;&lt;/img&gt;
    I've been playing around with some newfangled &lt;strong&gt;html5&lt;/strong&gt; techniques. Specifically &lt;strong&gt;localStorage&lt;/strong&gt; to easily persist data on a client browser, and &lt;strong&gt;contentEditable&lt;/strong&gt; to allow editing of html on the fly. Hop on over to &lt;a href="/workshop/lists/"&gt;chatch.es/workshop/lists/&lt;/a&gt; if you want to go straight to the demo&amp;hellip;

</summary>
    <content type="html">&lt;p&gt;
    &lt;img alt="screenshot example of quick lists" class="right" src="http://chatch.es/images/quick-lists-example.png"&gt;&lt;/img&gt;
    I've been playing around with some newfangled &lt;strong&gt;html5&lt;/strong&gt; techniques. Specifically &lt;strong&gt;localStorage&lt;/strong&gt; to easily persist data on a client browser, and &lt;strong&gt;contentEditable&lt;/strong&gt; to allow editing of html on the fly. Hop on over to &lt;a href="/workshop/lists/"&gt;chatch.es/workshop/lists/&lt;/a&gt; if you want to go straight to the demo.
&lt;/p&gt;


&lt;p&gt;
    I ran across this &lt;a href="http://html5demos.com/contenteditable" title="HTML5 Demo: ContentEditable"&gt;demo&lt;/a&gt; on &lt;a href="http://html5demos.com/" title="HTML5 Demos and Examples"&gt;html5demos.com&lt;/a&gt; which shows off editing some elements and saving them with localStorage so you can refresh the browser and your changes are still there. This is pretty neat in itself, but I ran with the concept and created a quick client-side task list.
&lt;/p&gt;




&lt;h2&gt;Features&lt;/h2&gt;




&lt;ul&gt;
    &lt;li&gt;Create, edit, remove, and complete items.&lt;/li&gt;
    &lt;li&gt;Add nested lists.&lt;/li&gt;
    &lt;li&gt;Save multiple lists by keying each one with a URL param (ex: &lt;a href="/workshop/lists/?MyList"&gt;chatch.es/workshop/lists/?MyList&lt;/a&gt;).&lt;/li&gt;
    &lt;li&gt;Lists have their name set as the page title. Making for nice bookmark-able lists.&lt;/li&gt;
    &lt;li&gt;Persisting list, even after browser is closed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;Under the hood&lt;/h2&gt;




&lt;p&gt;Each editable field has the &lt;em&gt;contenteditable&lt;/em&gt; attribute set.&lt;/p&gt;




&lt;pre class="textmate-source blackboard"&gt;&lt;span class="text text_html text_html_ruby"&gt;&lt;span class="meta meta_tag meta_tag_any meta_tag_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_html"&gt;h1&lt;/span&gt; &lt;span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_html"&gt;contenteditable&lt;/span&gt;=&lt;span class="string string_quoted string_quoted_double string_quoted_double_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_html"&gt;"&lt;/span&gt;true&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_html"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;gt;&lt;span class="meta meta_scope meta_scope_between-tag-pair meta_scope_between-tag-pair_html"&gt;&amp;lt;&lt;/span&gt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_html"&gt;h1&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;




&lt;p&gt;Each keystroke on an editable field will trigger the &lt;em&gt;save_state&lt;/em&gt; javascript helper function, which saves everything in the body element. A better solution would be to separate the markup from the data when saving, however the markup would have to be rebuilt with javascript on page load. Not worth the time to implement for a simple demo. The &lt;em&gt;get_list_name&lt;/em&gt; function is another helper that checks the URL for a list name. This keeps each separate list separate in the &lt;em&gt;localStorage&lt;/em&gt;.&lt;/p&gt;




&lt;pre class="textmate-source blackboard"&gt;&lt;span class="source source_js"&gt;&lt;span class="meta meta_function meta_function_js"&gt;&lt;span class="storage storage_type storage_type_function storage_type_function_js"&gt;function&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_js"&gt;save_state&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_begin punctuation_definition_parameters_begin_js"&gt;(&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_end punctuation_definition_parameters_end_js"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;
  localStorage&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;setItem&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;get_list_name&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;, &lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_js"&gt;$&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;body&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;html&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;())&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;
&lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;




&lt;p&gt;When the page is loaded, localStorage is checked to see if data has already been saved, in which case it is used to replace the body's inner html.&lt;/p&gt;




&lt;pre class="textmate-source blackboard"&gt;&lt;span class="source source_js"&gt;&lt;span class="keyword keyword_control keyword_control_js"&gt;if&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;localStorage&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;getItem&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;get_list_name&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()))&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;
  &lt;span class="storage storage_type storage_type_js"&gt;var&lt;/span&gt; saved_html &lt;span class="keyword keyword_operator keyword_operator_js"&gt;=&lt;/span&gt; localStorage&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;getItem&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;get_list_name&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;())&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;
  &lt;span class="keyword keyword_operator keyword_operator_js"&gt;$&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;body&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;html&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;saved_html&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;
&lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;




&lt;p&gt;jQuery is used to handle all the application logic. For a more detailed look, check out the &lt;a href="/scripts/lists.js"&gt;lists.js&lt;/a&gt; file.&lt;/p&gt;


&lt;p&gt;&lt;a class="kick-ass button" href="/workshop/lists/"&gt;Take me to the demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Runs great in Safari, Firefox, and Chrome. Unfortunately &lt;em&gt;contentEditable&lt;/em&gt; doesn't yet work in Mobile Safari. I haven't tested it in Opera or IE. &lt;/p&gt;

</content>
  </entry>
  <entry>
    <title>How to make a simple eye mask</title>
    <link rel="alternate" href="http://chatch.es/blog/2010/09/13/how-to-make-a-simple-eye-mask/"/>
    <id>http://chatch.es/blog/2010/09/13/how-to-make-a-simple-eye-mask/</id>
    <published>2010-09-13</published>
    <updated>2010-09-13</updated>
    <author>
      <name>philip</name>
    </author>
    <summary type="html">&lt;p&gt;
    &lt;img alt="cat wearing eye mask" class="right" src="http://chatch.es/images/cat-eye-mask.jpg"&gt;&lt;/img&gt;
    Recently I was confronted with the daunting task of sleeping on an airplane. I don't often fly on planes and even less often am I able to fall asleep in sitting positions. To tackle this problem I wanted all the tools I could muster without breaking my wallet on expensive travel gear. One such tool is the eye mask. This quick tutorial will show you how to make an eye mask using only a wash cloth and bit of elastic string. That's right, we're doing it Macgyver style&amp;hellip;

</summary>
    <content type="html">&lt;p&gt;
    &lt;img alt="cat wearing eye mask" class="right" src="http://chatch.es/images/cat-eye-mask.jpg"&gt;&lt;/img&gt;
    Recently I was confronted with the daunting task of sleeping on an airplane. I don't often fly on planes and even less often am I able to fall asleep in sitting positions. To tackle this problem I wanted all the tools I could muster without breaking my wallet on expensive travel gear. One such tool is the eye mask. This quick tutorial will show you how to make an eye mask using only a wash cloth and bit of elastic string. That's right, we're doing it Macgyver style.
&lt;/p&gt;




&lt;h2&gt;Materials:&lt;/h2&gt;




&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Bathroom washcloth&lt;/strong&gt; - approx. 12" by 12"&lt;/li&gt;
    &lt;li&gt;
        &lt;strong&gt;Elastic string&lt;/strong&gt; - approx. 20" (non-elastic string can be substituted, although the mask may not fit as snugly)
        &lt;br /&gt;
        &lt;img alt="eye-mask-materials" src="http://chatch.es/images/eye-mask-materials.jpg"&gt;&lt;/img&gt;
    &lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;Steps:&lt;/h2&gt;




&lt;ol&gt;
    &lt;li&gt;First fold the washcloth diagonally making a triangle.&lt;/li&gt;
    &lt;li&gt;Next, form a clove hitch on one end of the elastic string and pass one corner of the triangle through it. Check out the short video below to learn how to make a clove hitch.&lt;/li&gt;
    &lt;li&gt;Finally, make another clove hitch on the other end of the string, attaching it to the other corner of the wash cloth. You can adjust the length of the elastic by feeding the string through the hitch and pulling out the slack.&lt;/li&gt;
    &lt;li&gt;Slide the mask over your head with the third point of the triangle pointing down. The mask can be quickly assembled on the go and having a wash cloth on hand while traveling can be quite handy for cleaning up spills.&lt;/li&gt;
    
&lt;/ol&gt;




&lt;object width="720" height="565"&gt;&lt;param name="movie" value="http://www.youtube.com/v/iOS7p6rPg00?fs=1&amp;amp;hl=en_US&amp;amp;rel=0"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/iOS7p6rPg00?fs=1&amp;amp;hl=en_US&amp;amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="720" height="565"&gt;&lt;/embed&gt;&lt;/object&gt;




&lt;p&gt;Is that clove hitch kicking your butt? Check out &lt;a href="http://www.youtube.com/watch?v=aewgmUeHpuE" title="YouTube - How To Tie a Clove Hitch Knot"&gt;this video&lt;/a&gt; for an alternate tying method.&lt;/p&gt;




&lt;p&gt;Now if you'll excuse me, I'm going to take a little cat nap.&lt;/p&gt;

</content>
  </entry>
  <entry>
    <title>IKEA Product availability Notifier</title>
    <link rel="alternate" href="http://chatch.es/blog/2010/07/22/ikea-product-availability-notifier/"/>
    <id>http://chatch.es/blog/2010/07/22/ikea-product-availability-notifier/</id>
    <published>2010-07-22</published>
    <updated>2010-07-22</updated>
    <author>
      <name>philip</name>
    </author>
    <summary type="html">&lt;p&gt;
    &lt;img alt="example notifo notification on iPhone" class="right" src="http://chatch.es/images/notifo-ikea-iphone.jpg" /&gt;
    Waiting for &lt;a href="http://www.ikea.com/" title="Welcome to IKEA.com"&gt;IKEA&lt;/a&gt; to restock that new &lt;a href="http://www.ikea.com/us/en/catalog/products/S99877812" title="IKEA | Fabric sofas | Sofas | KIVIK | Sofa"&gt;KIVIK couch&lt;/a&gt; you're dying to park your bum on? You could manually check IKEA's website everyday or you could use a &lt;em&gt;web page change&lt;/em&gt; notification tool like &lt;a href="http://femtoo.com/" title="Femtoo - Web page change tracking and notification system"&gt;femtoo&lt;/a&gt;. However, the free version will only check every 12 hours. Sounds like a great opportunity to write a small &lt;strong&gt;Ruby scraper&lt;/strong&gt; that runs every 5 mins. Also, I've been looking for an excuse to test out the &lt;a href="https://api.notifo.com/"&gt;API&lt;/a&gt; of the notification service, &lt;strong&gt;Notifo&lt;/strong&gt;. With their &lt;a href="http://notifo.com/mobile_apps/iphone" title="Mobile Apps - iPhone - Notifo"&gt;iPhone app&lt;/a&gt; a nifty message will pop right up. Now if I could only replace that alert sound with &lt;a href="http://www.youtube.com/watch?v=XvazQUYG1kE" title="YouTube

</summary>
    <content type="html">&lt;p&gt;
    &lt;img alt="example notifo notification on iPhone" class="right" src="http://chatch.es/images/notifo-ikea-iphone.jpg" /&gt;
    Waiting for &lt;a href="http://www.ikea.com/" title="Welcome to IKEA.com"&gt;IKEA&lt;/a&gt; to restock that new &lt;a href="http://www.ikea.com/us/en/catalog/products/S99877812" title="IKEA | Fabric sofas | Sofas | KIVIK | Sofa"&gt;KIVIK couch&lt;/a&gt; you're dying to park your bum on? You could manually check IKEA's website everyday or you could use a &lt;em&gt;web page change&lt;/em&gt; notification tool like &lt;a href="http://femtoo.com/" title="Femtoo - Web page change tracking and notification system"&gt;femtoo&lt;/a&gt;. However, the free version will only check every 12 hours. Sounds like a great opportunity to write a small &lt;strong&gt;Ruby scraper&lt;/strong&gt; that runs every 5 mins. Also, I've been looking for an excuse to test out the &lt;a href="https://api.notifo.com/"&gt;API&lt;/a&gt; of the notification service, &lt;strong&gt;Notifo&lt;/strong&gt;. With their &lt;a href="http://notifo.com/mobile_apps/iphone" title="Mobile Apps - iPhone - Notifo"&gt;iPhone app&lt;/a&gt; a nifty message will pop right up. Now if I could only replace that alert sound with &lt;a href="http://www.youtube.com/watch?v=XvazQUYG1kE" title="YouTube
- Emeril BAM!!!"&gt;Emeril's Bam&lt;/a&gt;...   &lt;/p&gt;




&lt;h2&gt;Prerequisites&lt;/h2&gt;




&lt;ul&gt;
    &lt;li&gt;Unix-like system. I'm gonna assume you know how to use the command line. You don't need to be an expert or anything.&lt;/li&gt;
    &lt;li&gt;Ruby&lt;/li&gt;
    &lt;li&gt;Rubygems&lt;/li&gt;
    &lt;li&gt;Git&lt;/li&gt;
    &lt;li&gt;
        iPhone (Don't have an iPhone? No worries, you can still check your notifications on &lt;a href="http://notifo.com/" title="notifo - Home"&gt;notifo.com&lt;/a&gt;)
    &lt;/li&gt;
    &lt;li&gt;
        &lt;strong&gt;Update:&lt;/strong&gt; Notifo now has a &lt;a href="http://notifo.com/desktop" title="Desktop Apps - Notifo"&gt;Desktop Mac client&lt;/a&gt; that uses Growl and a &lt;a href="http://notifo.com/browser_extensions" title="Web Browser Extensions - Notifo"&gt;Google Chrome extension&lt;/a&gt;.
    &lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;Setup&lt;/h2&gt;




&lt;p&gt;First you need to set up a Notifo account. Head over to &lt;a href="http://notifo.com/" title="notifo - Home"&gt;notifo.com&lt;/a&gt; and set one up. If you've got an iPhone now's the time to install the &lt;a href="http://notifo.com/mobile_apps/iphone" title="Mobile Apps - iPhone - Notifo"&gt;Notifo app&lt;/a&gt; and link it to your newly created account.&lt;/p&gt;




&lt;p&gt;Next install the nokogiri gem,  We'll need it to parse IKEA's product availability page.&lt;/p&gt;


&lt;p&gt;&lt;code class="console"&gt;$ gem install nokogiri&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There isn't an official API gem from Notifo yet. Jot has a &lt;a href="http://github.com/jot/notifo" title="jot's notifo at master - GitHub"&gt;gem&lt;/a&gt; on github which I've &lt;a href="http://github.com/pkelly/notifo" title="pkelly's notifo at master - GitHub"&gt;forked&lt;/a&gt; to fix a bug in which you couldn't set the label attribute for notifications. Create a working directory to clone my github repository to, like "ikea-notifo." &lt;em&gt;cd&lt;/em&gt; into that dir and type in the following.&lt;/p&gt;


&lt;p&gt;&lt;code class="console"&gt;$ git clone git://github.com/pkelly/notifo.git&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now you're working folder should contain a folder called "notifo."&lt;/p&gt;




&lt;p&gt;Fire up your favorite text editor and paste in the below code.&lt;/p&gt;




&lt;pre class="textmate-source blackboard"&gt;
&lt;code&gt;&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;rubygems&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;nokogiri&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;open-uri&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;notifo/lib/notifo.rb&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

search_url &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;http://www.ikea.com/us/en/catalog/availability/S79877813/emeryville&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;

&lt;span class="keyword keyword_control keyword_control_ruby"&gt;while&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do
&lt;/span&gt;  doc &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Nokogiri&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;HTML&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;open&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;search_url&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;))&lt;/span&gt;

  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; doc&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;css&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;div.sc_graph_product&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;inner_text &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;=~&lt;/span&gt; &lt;span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;out of stock&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;/span&gt;
    puts &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;No sofas in stock at &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Time&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;now&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;, better luck next time...&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;else&lt;/span&gt;
    puts &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;W00t! Sofa in stock!&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;
    puts &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;I'll give you the good news with a nifty notification!&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;

    user &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;chatche&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;
    label &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;IKEA&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;
    title &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;Kivik Sofa&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;
    message &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Good news! The sofa is in stock. Welcome to WooTown, USA pop. you!&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
    uri &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; search_url

    notifocation &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Notifo&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;user&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;put your Notifo api key here&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    notifocation&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;post&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;user&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; message&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; title&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; uri&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; label&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby"&gt;break&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
  sleep&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;60&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;*&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;5&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;p&gt;Let's break this script down a bit:&lt;/p&gt;




&lt;ul&gt;
    &lt;li&gt;We've got &lt;em&gt;nokogiri&lt;/em&gt; required at the top, the standard library &lt;em&gt;open-uri&lt;/em&gt;, and notifo.rb that you cloned from github. Next, the IKEA URL is set.&lt;/li&gt;
    &lt;li&gt;An infinite loop is opened up and the html is fetched.&lt;/li&gt;
    &lt;li&gt;A CSS selector is used to find the html element that might contain the "out of stock" message.&lt;/li&gt;
    &lt;li&gt;If the product is still out of stock, a message is printed to the console and the script waits 5 minutes before checking again.&lt;/li&gt;
    &lt;li&gt;Once the product is in stock the notification is created and script ends.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;You'll have to change &lt;strong&gt;3 things&lt;/strong&gt; in this script:&lt;/p&gt;




&lt;ol&gt;
    &lt;li&gt;
        First change &lt;em&gt;search_url&lt;/em&gt; to the out of stock page of your desired IKEA product. You can find it by first going to a product page, like this &lt;a href="http://www.ikea.com/us/en/catalog/products/S99877812" title="IKEA | Fabric sofas | Sofas | KIVIK | Sofa"&gt;KIVIK sofa one&lt;/a&gt;. In the &lt;em&gt;Buy at your local store&lt;/em&gt; box on the right, select the closest IKEA and click &lt;em&gt;Check stock availability&lt;/em&gt;. The resulting page should look similar to the below screenshot.
        &lt;img alt="ikea product out of stock example" src="http://chatch.es/images/ikea-product-out-of-stock.png" /&gt;
        &lt;p&gt;Once a product is in stock the page will look like this.&lt;/p&gt;
        &lt;img alt="ikea product in stock example" src="http://chatch.es/images/ikea-product-in-stock.png" /&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;Change &lt;em&gt;user&lt;/em&gt; to your Notifo username.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;In the line that contains "Notifo.new" paste in your Notifo secret API key. You can find it by logging in to &lt;a href="http://notifo.com/" title="notifo - Home"&gt;notifo.com&lt;/a&gt; and clicking &lt;em&gt;Settings&lt;/em&gt;.&lt;/p&gt;
    &lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Save this file as "ikea.rb" in the working directory we created earlier. That folder should now contain ikea.rb and the notifo folder.&lt;/p&gt;




&lt;p&gt;Now you're ready to rock n roll! Well more like execute some ruby code and wait for a notification. But you can still rock your ass off while you do that.&lt;/p&gt;


&lt;p&gt;&lt;code class="console"&gt;$ ruby ikea.rb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once your IKEA product is in stock your phone will let you know. Tap the notification in Notifo to go the IKEA URL and see how many are in stock.&lt;/p&gt;




&lt;p&gt;When you shutdown your computer the script is of course going to stop running which is why you should run it on a server. If you don't have access to a server you can just leave your computer on. It only took a few days for them to restock my KIVIK sofa.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Pro tip&lt;/strong&gt;: Make sure all your Notifo information is correct by testing on an IKEA URL that has an in stock product.&lt;/p&gt;




&lt;script type="text/javascript"&gt;
        var disqus_url = 'http://chatch.es/2010/07/22/ikea-product-availability-notifier/';
&lt;/script&gt;

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