<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Pivotal Labs</title>
	<atom:link href="http://pivotallabs.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://pivotallabs.com</link>
	<description>Agility Developed</description>
	<lastBuildDate>Tue, 18 Jun 2013 22:21:46 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Populating Null Keys using OS X&#8217;s PlistBuddy</title>
		<link>http://pivotallabs.com/creating-null-keys-using-os-xs-plistbuddy/</link>
		<comments>http://pivotallabs.com/creating-null-keys-using-os-xs-plistbuddy/#comments</comments>
		<pubDate>Tue, 18 Jun 2013 20:52:10 +0000</pubDate>
		<dc:creator>Brian Cunnie</dc:creator>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[keys]]></category>
		<category><![CDATA[null]]></category>
		<category><![CDATA[PlistBuddy]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20399</guid>
		<description><![CDATA[<p>Abstract Apple OS X&#8217;s PlistBuddy is a tool for modifying p-list (i.e. Property List, .plist) files; however, it has difficulty populating null keys (though little difficulty creating them). This blog post describes a method of using PlistBuddy to populate null keys by first creating &#38; populating a placeholder key and then using the copy directive to populate the null key. Creating the Null Key is Easy Creating the null key is easy; use a double-colon (&#8220;::&#8221;): /usr/libexec/PlistBuddy -c "add :: dict" /tmp/junk.plist; cat /tmp/junk.plist File Doesn't Exist, Will Create: /tmp/junk.plist &#60;?xml version="1.0" encoding="UTF-8"?&#62; &#60;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&#62; &#60;plist version="1.0"&#62; &#60;dict&#62; &#60;key&#62;&#60;/key&#62; &#60;dict/&#62; &#60;/dict&#62; &#60;/plist&#62; Populating the Null Key: the Right Way Populate the null key by first creating a placeholder key, populating that, and then copying it to the null key: rm /tmp/junk.plist /usr/libexec/PlistBuddy -c "add :placeholder dict" /tmp/junk.plist /usr/libexec/PlistBuddy -c "add :placeholder:nullKeySubKey string 'hello'" /tmp/junk.plist /usr/libexec/PlistBuddy&#8230;</p><p>The post <a href="http://pivotallabs.com/creating-null-keys-using-os-xs-plistbuddy/">Populating Null Keys using OS X&#8217;s PlistBuddy</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<h3>Abstract</h3>
<p>Apple OS X&#8217;s <a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man8/PlistBuddy.8.html">PlistBuddy</a> is a tool for modifying <a href="https://en.wikipedia.org/wiki/Property_list">p-list</a> (i.e. Property List, .plist) files; however, it has difficulty populating null keys (though little difficulty <em>creating</em> them). This blog post describes a method of using PlistBuddy to populate null keys by first creating &amp; populating a placeholder key and then using the copy directive to populate the null key.</p>
<h3>Creating the Null Key is Easy</h3>
<p>Creating the null key is easy; use a double-colon (&#8220;::&#8221;):</p>
<pre><code>/usr/libexec/PlistBuddy -c "add :: dict" /tmp/junk.plist; cat /tmp/junk.plist
File Doesn't Exist, Will Create: /tmp/junk.plist
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
&lt;dict&gt;
  &lt;key&gt;&lt;/key&gt;
  &lt;dict/&gt;
&lt;/dict&gt;
&lt;/plist&gt;
</code></pre>
<h3>Populating the Null Key: the Right Way</h3>
<p>Populate the null key by first creating a placeholder key, populating that, and then copying it to the null key:</p>
<pre><code>
rm /tmp/junk.plist
/usr/libexec/PlistBuddy -c "add :placeholder dict" /tmp/junk.plist
/usr/libexec/PlistBuddy -c "add :placeholder:nullKeySubKey string 'hello'" /tmp/junk.plist
/usr/libexec/PlistBuddy -c "copy :placeholder ::" /tmp/junk.plist
/usr/libexec/PlistBuddy -c "delete :placeholder" /tmp/junk.plist
cat /tmp/junk.plist
....
&lt;dict&gt;
  &lt;key&gt;&lt;/key&gt;
  &lt;dict&gt;
    &lt;key&gt;nullKeySubKey&lt;/key&gt;
    &lt;string&gt;hello&lt;/string&gt;
  &lt;/dict&gt;
&lt;/dict&gt;
...</code></pre>
<h3>Things that Should Work but Don&#8217;t</h3>
<p>In general, PlistBuddy will concatenate a double-colon (&#8220;::&#8221;) into one (&#8220;:&#8221;). So the key <code>::nullKeySubKey</code> is treated as <code>:nullKeySubKey</code>, i.e.<br />
<code>/usr/libexec/PlistBuddy -c "add /usr/libexec/PlistBuddy -c "add ::nullKeySubKey string 'hello'" /tmp/junk.plist</code> will not create a null key.</p>
<p>Attempts to trick PlistBuddy with an empty string (e.g. &#8220;&#8221;) won&#8217;t work, either. <code>/usr/libexec/PlistBuddy -c "add :'':nullKeySubKey string 'hello'" /tmp/junk.plist</code> will not create a null key.</p>
<h3>Real World Example of Null Keys</h3>
<p>The ~/Library/Preferences/com.apple.desktop.plist is a typical p-list file that contains a null key. First, we&#8217;ll convert the p-list from binary to XML using plutil, and then we&#8217;ll examine the XML to confirm that there is a null key:</p>
<pre><code>plutil -convert xml1 ~/Library/Preferences/com.apple.desktop.plist
less ~/Library/Preferences/com.apple.desktop.plist
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
&lt;dict&gt;
  &lt;key&gt;Background&lt;/key&gt;
  &lt;dict&gt;
    &lt;key&gt;spaces&lt;/key&gt;
    &lt;dict&gt;
      &lt;key&gt;&lt;/key&gt;
...
</code></pre>
<p>The post <a href="http://pivotallabs.com/creating-null-keys-using-os-xs-plistbuddy/">Populating Null Keys using OS X&#8217;s PlistBuddy</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/creating-null-keys-using-os-xs-plistbuddy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pingpongapalooza</title>
		<link>http://pivotallabs.com/pingpongapalooza/</link>
		<comments>http://pivotallabs.com/pingpongapalooza/#comments</comments>
		<pubDate>Tue, 18 Jun 2013 16:25:45 +0000</pubDate>
		<dc:creator>whiteboard</dc:creator>
				<category><![CDATA[Standup]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20398</guid>
		<description><![CDATA[<p>Helps Best non-paperclip solution for S3? There was a question about uploading to S3 on an iOS project backed by non-rails ruby. Best practice (Rails or not) seems to be using the AWS gem to generate URLS, send those to the phone, and do all the manipulation and uploading from the device. Events Tuesday: Homefrys Ping Pong Tournament!!!!!!! Ping pong tournament with other startups @ Pivotal Labs. We have 2 teams made up of: Palermo and Phan, and Michael and Danny. Come cheer us on!</p><p>The post <a href="http://pivotallabs.com/pingpongapalooza/">Pingpongapalooza</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<h2>Helps</h2>
<h3>Best non-paperclip solution for S3?</h3>
<p>There was a question about uploading to S3 on an iOS project backed by non-rails ruby.</p>
<p>Best practice (Rails or not) seems to be using the AWS gem to generate URLS, send those to the phone, and do all the manipulation and uploading from the device.</p>
<h2>Events</h2>
<h3>Tuesday: Homefrys Ping Pong Tournament!!!!!!!</h3>
<p>Ping pong tournament with other startups @ Pivotal Labs. We have 2 teams made up of: Palermo and Phan, and Michael and Danny. Come cheer us on!</p>
<p>The post <a href="http://pivotallabs.com/pingpongapalooza/">Pingpongapalooza</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/pingpongapalooza/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bulletproof font-face syntax with SASS</title>
		<link>http://pivotallabs.com/bulletproof-font-face-syntax-with-sass/</link>
		<comments>http://pivotallabs.com/bulletproof-font-face-syntax-with-sass/#comments</comments>
		<pubDate>Tue, 18 Jun 2013 03:38:22 +0000</pubDate>
		<dc:creator>Ward Penney</dc:creator>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[ironblogger]]></category>
		<category><![CDATA[SASS]]></category>
		<category><![CDATA[webfonts]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20371</guid>
		<description><![CDATA[<p>The Bulletproof font-face syntax effectively gives you broad browser support for your fancy (or austere) web fonts. However, using the Bulletproof font-face syntax with SASS carries a couple of gotchas. Reference this article when you are starting a new project and setting up the fonts. TL;DR A handy mixin Step 1: Use this: // // mixin for bullet proof font declaration syntax // @mixin declare-font-face($font-family, $font-filename, $font-weight : normal, $font-style :normal, $font-stretch : normal) { @font-face { font-family: '#{$font-family}'; src: url(font-path('#{$font-filename}.eot')); src: url(font-path('#{$font-filename}.eot?#iefix')) format('embedded-opentype'), url(font-path('#{$font-filename}.woff')) format('woff'), url(font-path('#{$font-filename}.ttf')) format('truetype'), url(font-path('#{$font-filename}.svg##{$font-family}')) format('svg'); font-weight: $font-weight; font-style: $font-style; font-stretch: $font-stretch; } } Step 2: Write one line for each of your fonts you include: @include declare-font-face('Gill Sans', 'Gill-Sans-MT-Pro-Light', 200); @include declare-font-face('Gill Sans', 'Gill-Sans-MT-Pro-Italic', 400, italic); Step 3: Party The Tricks of Bulletproof font-face syntax with SASS It uses SCSS syntax, because SCSS can do multi-line and SASS can’t. It’s fine if you use SASS syntax, just&#8230;</p><p>The post <a href="http://pivotallabs.com/bulletproof-font-face-syntax-with-sass/">Bulletproof font-face syntax with SASS</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>The Bulletproof font-face syntax effectively gives you broad browser support for your fancy (or austere) web fonts. However, using the Bulletproof font-face syntax with SASS carries a couple of gotchas. Reference this article when you are starting a new project and setting up the fonts.</p>
<h2>TL;DR A handy mixin</h2>
<h3>Step 1: Use this:</h3>
<pre><code>
//
// mixin for bullet proof font declaration syntax
//
@mixin declare-font-face($font-family, $font-filename, $font-weight : normal, $font-style :normal, $font-stretch : normal) {
@font-face {
font-family: '#{$font-family}';
src: url(font-path('#{$font-filename}.eot'));
src: url(font-path('#{$font-filename}.eot?#iefix')) format('embedded-opentype'),
url(font-path('#{$font-filename}.woff')) format('woff'),
url(font-path('#{$font-filename}.ttf')) format('truetype'),
url(font-path('#{$font-filename}.svg##{$font-family}')) format('svg');
font-weight: $font-weight;
font-style: $font-style;
font-stretch: $font-stretch;
}
}
</code></pre>
<h3>Step 2: Write one line for each of your fonts you include:</h3>
<pre><code>
@include declare-font-face('Gill Sans', 'Gill-Sans-MT-Pro-Light', 200);
@include declare-font-face('Gill Sans', 'Gill-Sans-MT-Pro-Italic', 400, italic);
</code></pre>
<h3>Step 3: Party</h3>
<h2>The Tricks of Bulletproof font-face syntax with SASS</h2>
<p>It uses SCSS syntax, because SCSS can do multi-line and SASS can’t. It’s fine if you use SASS syntax, just name this file .scss and @import it just the same.</p>
<p>The mixin has defaults for last three parameters (denoted by the colons in the method signature). This way, you don’t have to go out of your way to specify normal each time.</p>
<p>It uses the font-path inside of the url(&#8230;). That is because I have seen lots of bugs with complex file names for the font files, and the quotes guarantee the file will be found. Either rename all your fonts with no dashes or spaces or other weird characters, or use this trick.</p>
<p>This isn’t really a trick, but it is more convienent to put all font variants inside the same font-family. It just makes it easier to have everything as “Gill Sans” and change the font-weight: italic, rather than having “Gill Sans” and “Gill Sans Italic” and however other many variants you have.</p>
<p>The original trick: Originally developed by Paul Irish (<a title="Paul Irish's Bulletproof font-face syntax" href="http://www.paulirish.com/2009/bulletproof-font-face-implementation-syntax/">Bulletproof font-face syntax</a>) and more recently by Fontspring (<a title="Fontspring's New Bulletproof Syntax" href="http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax">The New Bulletproof syntax</a>), the syntax gives you broad browser support for your web fonts. IE8 loads the first .eot file and is done, but it &#8220;tricks&#8221; IE9 by relying on a bug in the parser. It dies on the question mark in the second line, and doesn&#8217;t continue on to the other file formats (which don&#8217;t work in IE9, and would cause it to not display). The other formats are handled by Safari, Chrome and Firefox, and carry no such trickery.</p>
<h2>Thank You</h2>
<p>And be sure to <a title="wardpenney on Twitter" href="http://twitter.com/wardpenney" target="_blank">follow me on twitter</a> for new fancy posts!</p>
<p>The post <a href="http://pivotallabs.com/bulletproof-font-face-syntax-with-sass/">Bulletproof font-face syntax with SASS</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/bulletproof-font-face-syntax-with-sass/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>When is done, done?</title>
		<link>http://pivotallabs.com/when-is-done-done/</link>
		<comments>http://pivotallabs.com/when-is-done-done/#comments</comments>
		<pubDate>Tue, 18 Jun 2013 02:18:28 +0000</pubDate>
		<dc:creator>Graham Siener</dc:creator>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[100 things]]></category>
		<category><![CDATA[ironblogger]]></category>
		<category><![CDATA[lean development]]></category>
		<category><![CDATA[pm]]></category>
		<category><![CDATA[product management]]></category>
		<category><![CDATA[product market fit]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20367</guid>
		<description><![CDATA[<p>When you get into the rhythm of pushing new features through the product development lifecycle, it can be addictive.  Theoretically every new push brings more customer value, so why not keep going?  Restated, when should you stop writing code and put your efforts elsewhere? If you assume that you’ll never truly know (except in a vacuum), I think there are two main factors to consider:  First, every feature you implement requires justification to build and effort to maintain.  Second, if you are following lean principles it’s important to create valid experiments by measuring the viability of your current product, not one that is constantly shifting. Let’s break that down. Every New Feature Costs Something Internalizing the lifetime cost of everything you build is critical to your [and your customers’] sanity.  A friend of mine recently endeavored to simplify her life by trying the 100 thing challenge.  Take a look at&#8230;</p><p>The post <a href="http://pivotallabs.com/when-is-done-done/">When is done, done?</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p dir="ltr">When you get into the rhythm of pushing new features through the product development lifecycle, it can be addictive.  Theoretically every new push brings more customer value, so why not keep going?  Restated, <em>when should you stop writing code and put your efforts elsewhere?</em></p>
<p dir="ltr">If you assume that you’ll never truly know (except in a vacuum), I think there are two main factors to consider:  First, every feature you implement requires justification to build and effort to maintain.  Second, if you are following lean principles it’s important to create valid experiments by measuring the viability of your current product, not one that is constantly shifting.</p>
<p dir="ltr">Let’s break that down.</p>
<h1 dir="ltr">Every New Feature Costs Something</h1>
<p dir="ltr">Internalizing the lifetime cost of everything you build is critical to your [and your customers’] sanity.  A friend of mine recently endeavored to simplify her life by trying the <a href="http://www.100thingchallenge.com/about-100tc/">100 thing challenge</a>.  Take a look at the three driving principles and you’ll see the parallels to product development:</p>
<ol>
<li dir="ltr">
<p dir="ltr">Reduce by reducing the number of our possessions for an extended period of time, we prove to ourselves that consumerism does not define us</p>
</li>
<li dir="ltr">
<p dir="ltr">Refuse by refusing to go along with in the misleading lifestyle of consumerism, we form new priorities in line with personal virtue and what is best for the world around us</p>
</li>
<li dir="ltr">
<p dir="ltr">Rejigger by rejiggering our lives through simplicity, we nurture better relationships with family and community and nature</p>
</li>
</ol>
<p dir="ltr">If you ignore the preachiness, this can serve as a template for your product.  Don’t add new features just for the sake of it.  The best apps do something specific, and do it very well.  Refuse to add something that serves as a barrier between your customers and derived value just because it’s an emerging trend.  Lastly, by focusing on the relationship your customer has with your product, you’ll shift focus from business-centric to customer-centric interaction goals.</p>
<h1 dir="ltr">Your Product Should Sell Itself (Eventually)</h1>
<p>The purpose of shipping early and often is to err on the side of learning too much.  If you’re launching a new product, chances are you’re only going after early adopters.  These people LOVE using unfinished products, since the chance of finding something that exactly addresses their wants/needs is high.  These initial customers probably try 10 new services a week.  Instead of chasing their wish list, you should figure out their common thread and target more of their peers.  Reach out to them and figure out which part of your value proposition they care about &#8212; this messaging should be clear and consistent throughout your marketing and product (i.e., product/market fit).  If you can tune this acquisition engine, you should see clear improvement in your cohorts without additional feature work.</p>
<h1 dir="ltr">Keep Building Tools</h1>
<p dir="ltr">The caveat emptor to the above advice is that you can never have too many tools at your disposal.  While your product may be “good enough,” the instrumentation you use to measure your product are probably not.  Devote some dev cycles to email tracking, behavioral metrics and personalized drip campaigns.  Some might argue these are core product enhancements, even if they&#8217;re invisible (when done well).  If they are helping you attract and engage new customers, I think it&#8217;s a moot point &#8212; just make sure that you&#8217;re not spending your time building the perfect product at the expense of one that&#8217;s good enough.</p>
<p>The post <a href="http://pivotallabs.com/when-is-done-done/">When is done, done?</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/when-is-done-done/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tracking Nairobi Dev Camp</title>
		<link>http://pivotallabs.com/tracking-nairobi-dev-camp/</link>
		<comments>http://pivotallabs.com/tracking-nairobi-dev-camp/#comments</comments>
		<pubDate>Mon, 17 Jun 2013 22:38:52 +0000</pubDate>
		<dc:creator>Marlena Compton</dc:creator>
				<category><![CDATA[Tracker]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20359</guid>
		<description><![CDATA[<p>On the Tracker team, I love hearing great stories about our users and the things they are able to accomplish using agile methodologies and collaboration.  I’m also a woman in tech and have a keen interest in supporting other women as well as other diverse groups who work persistently to reach their goals in tech.  One story I’ve been following lately is the story of Tracker user Martha Chelimo Njeri Chumo (&#8220;Njeri&#8221;) and her teammates. After raising funds, Njeri was set to attend this summer’s Hacker school in New York.  Unfortunately she was denied a visa by the U.S. consulate in Kenya, curtailing her original plans. It’s very easy when facing something beyond your own control to give up or to become discouraged.  Njeri, however, was able to completely turn the tables on this setback by looking towards her own community and reaching for collaboration.  Today, Njeri and her teammates are making&#8230;</p><p>The post <a href="http://pivotallabs.com/tracking-nairobi-dev-camp/">Tracking Nairobi Dev Camp</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>On the Tracker team, I love hearing great stories about our users and the things they are able to accomplish using agile methodologies and collaboration.  I’m also a woman in tech and have a keen interest in supporting other women as well as other diverse groups who work persistently to reach their goals in tech.  One story I’ve been following lately is the story of Tracker user Martha Chelimo Njeri Chumo (&#8220;Njeri&#8221;) and her teammates.</p>
<p>After raising funds, Njeri was set to attend this summer’s Hacker school in New York.  Unfortunately she was denied a visa by the U.S. consulate in Kenya, curtailing her original plans.</p>
<p>It’s very easy when facing something beyond your own control to give up or to become discouraged.  Njeri, however, was able to completely turn the tables on this setback by looking towards her own community and reaching for collaboration.  Today, Njeri and her teammates are making plans to set up Nairobi’s own hacker school:  Nairobi Dev Camp.</p>
<p>While I’ve given the Nairobi Dev School some support on my own, I decided to take a lesson from them and rope in my own team to support her cause.</p>
<p>Unsurprisingly, the rest of the Tracker team was also inspired by Njeri’s determination and wanted to pass her story along.  While she still has a lot of work ahead of her to make this camp a reality, she also recognizes that she can’t do it alone, which is why she launched a <a href="http://www.google.com/url?q=http%3A%2F%2Fwww.indiegogo.com%2Fprojects%2Fnairobi-dev-school%2Fx%2F3616444&amp;sa=D&amp;sntz=1&amp;usg=AFQjCNEtxeo18-Dm-utdPNjcbqNUWpY-EA">campaign for Nairobi Dev School on Indiegogo</a>.</p>
<p>We hope that you will be as moved as we are and help the Nairobi Dev School anyway you see fit.  We wish Njeri and her teammates success.</p>
<p>The post <a href="http://pivotallabs.com/tracking-nairobi-dev-camp/">Tracking Nairobi Dev Camp</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/tracking-nairobi-dev-camp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>4th Floor: Now with more breakfast</title>
		<link>http://pivotallabs.com/4th-floor-now-with-more-breakfast/</link>
		<comments>http://pivotallabs.com/4th-floor-now-with-more-breakfast/#comments</comments>
		<pubDate>Mon, 17 Jun 2013 16:36:57 +0000</pubDate>
		<dc:creator>whiteboard</dc:creator>
				<category><![CDATA[Standup]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20346</guid>
		<description><![CDATA[<p>Interestings XP at Pivotal Labs Will Read &#38; ex-pivot Josh Susser talk with folks like Avdi Grimm about XP and what it looks like at Pivotal Labs. ~1hr. http://rubyrogues.com/109-rr-extreme-programming-with-will-read/</p><p>The post <a href="http://pivotallabs.com/4th-floor-now-with-more-breakfast/">4th Floor: Now with more breakfast</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<h2>Interestings</h2>
<h3>XP at Pivotal Labs</h3>
<p>Will Read &amp; ex-pivot Josh Susser talk with folks like Avdi Grimm about XP and what it looks like at Pivotal Labs. ~1hr.<br />
<a href="http://rubyrogues.com/109-rr-extreme-programming-with-will-read/">http://rubyrogues.com/109-rr-extreme-programming-with-will-read/</a></p>
<p>The post <a href="http://pivotallabs.com/4th-floor-now-with-more-breakfast/">4th Floor: Now with more breakfast</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/4th-floor-now-with-more-breakfast/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>To build a bookmarklet</title>
		<link>http://pivotallabs.com/to-build-a-bookmarklet/</link>
		<comments>http://pivotallabs.com/to-build-a-bookmarklet/#comments</comments>
		<pubDate>Mon, 17 Jun 2013 12:32:25 +0000</pubDate>
		<dc:creator>Robbie Clutton</dc:creator>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[bookmark]]></category>
		<category><![CDATA[bookmarklet]]></category>
		<category><![CDATA[iframe]]></category>
		<category><![CDATA[ironblogger]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20340</guid>
		<description><![CDATA[<p>Building a bookmarklet provides an interesting challenge. It involves interaction a website your application does not control where that site could be anything with any number of dependencies on CSS or Javascript libraries. The first choice to make is trying to work with that website and probably setting an !important on every CSS selector used and hope that there&#8217;s no namespace or versioning clashes with any Javascript included; or use an iframe. Iframes seem to have fallen out of favour in recent times but the sandboxed nature of the content inside an iframe mean the worries of CSS and Javascript clashes are gone. However this is replaced with a communications overhead of communicating between the host document and the iframe. I wanted to touch on some of the things our team did on a recent project to try and make this fairly seamless. Getting into the DOM A bookmarklet is&#8230;</p><p>The post <a href="http://pivotallabs.com/to-build-a-bookmarklet/">To build a bookmarklet</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>Building a bookmarklet provides an interesting challenge. It involves interaction a website your application does not control where that site could be anything with any number of dependencies on CSS or Javascript libraries. The first choice to make is trying to work with that website and probably setting an <code>!important</code> on every CSS selector used and hope that there&#8217;s no namespace or versioning clashes with any Javascript included; or use an iframe.</p>
<p>Iframes seem to have fallen out of favour in recent times but the sandboxed nature of the content inside an iframe mean the worries of CSS and Javascript clashes are gone. However this is replaced with a communications overhead of communicating between the host document and the iframe. I wanted to touch on some of the things our team did on a recent project to try and make this fairly seamless.</p>
<h2>Getting into the DOM</h2>
<p>A bookmarklet is a small piece of Javascript that a user can drag onto the bookmark bar and upon pressing the link the Javascript will run. Because there is no guarentee what site will be loaded and if that will have any number of Javascript libraries included it&#8217;s best to use plain old Javascript to create an iframe element and append it to the body of the document. Our bookmarklet also needed to have some javascript if for nothing else but to be able to dismiss and remove the newly created elements. This can be done through the creation of a script element and appending to the body just like the iframe itself.</p>
<p>Once the iframe and script tags are appended they are treated the same as any other element. The content is loaded and the script is executed. The next step is getting the window to talk to the iframe.  As a convienence the domain with protocol and port of the iframe is stored in a variable for later use.</p>
<pre><code>element = document.createElement('iframe');
element.id = 'example_iframe';
element.src = 'example.com?referrer=' + window.location;
document.body.appendChild(element);

script = document.createElement('script');
script.src = 'example.com/bookmark.js';
document.body.appendChild(script);
</code></pre>
<p>The location is also sent to the remote server to load the iframe so that it can also store that location for passing messages to the host.</p>
<p>At this point this Javascript could also append a script tag to a version of libraries that may be required for it&#8217;s own application to run. It could also test for the existance of that library before hand so it doesn&#8217;t bring down an incompatible version. For example, bringing in jquery:</p>
<pre><code>if ($ === undefined) {
    var jq = document.createElement('script');
    jq.src = "//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js";
    document.body.appendChild(jq);
}
</code></pre>
<h2>Sending a message</h2>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage">postmessage</a> method is available to communicate bewtween the window and the iframe.  The host window with a reference to the iframe can call <code>postmessage</code> with a string as a message and as a security measure the target location. We had stored this during the loading of the elements as described above.</p>
<pre><code>iframe.postmessage('hello', 'www.example.com');
</code></pre>
<p>That message won&#8217;t get anywhere unless the iframe is listening for the <code>message</code> event on the other end.</p>
<pre><code>// native Javascript
window.addEventListener('message', function(event){ … });

// jQuery
$(window).on('message', function(event){ … });
</code></pre>
<p>I&#8217;ve used the native Javascript above but really, once in the iframe itself the application has full control and could use JQuery or any other library at this point. Our application needs to listen to messages on both sides though so we needed the above to run in the host anyway.</p>
<h2>RPC</h2>
<p>Sending a message is all well and good but any non-trival application is going to have more than one function to run. We took influence from <a href="http://en.wikipedia.org/wiki/Remote_procedure_call">Remote Procedure Calls (RPC)</a> to call functions within the host and remote sites. The message sent was stringified JSON with a very light &#8216;schema&#8217; of the function to run and parameters to send to the function.</p>
<pre><code>{   
    f: 'theFunction',
    params: {
        ...
    }
}
</code></pre>
<p>The recipient could then parse the string it knew to be JSON, extract the function to call and call it with any optional parameters also sent. This does create a binding between the host and the iframe but as the appliction controlled both sides we deemed it an acceptable risk.  The function can be run from the <code>window</code> like so:</p>
<pre><code>window['theFunction']();

// or from the event listener
var fn = JSON.parse(event.data).['f'];
window[fn]();
</code></pre>
<h2>Dealing with namespaces</h2>
<p>It was mentioned earlier that one of the goals of using an iframe was not to clobber any Javascript namespaces but we did end up including Javascript in the host and to avoid this we used an application namespace. However calling that as a property on the <code>window</code> would no longer work.</p>
<pre><code>// doesn't work
window['my.app.function'](); 

// works
window['my']['app']['function']();
</code></pre>
<p>We looked to <a href="https://github.com/elementaljs">ElementalJS</a> as an example of dealing with namespaced functions to parse the function.</p>
<pre><code>window.addEventListener('message', function(){
    var fn = window; 
    var data = JSON.parse(event.data);
    var namespaced = data['f'].split('.');
    for (var i in namespaced) { 
        fn = fn[namespaced[i]];
    }
    fn(data.params);    
});
</code></pre>
<p>This is natually fairly crude, some defensive code could be added but this demonstrates the intent of the processing. Defense like making sure that function existed, or that &#8216;f&#8217; existed in the data for the window could receive a message from another iframe.</p>
<h2>Putting it all together</h2>
<p>The bookmarket inserts two elements, an iframe and a script. The iframe has the source <code>example.com?referer=bar.com</code>. <code>bar.com</code> is inserted as a variable in the iframe Javascript code.  The iframe inserted has an id of <code>example_iframe</code></p>
<p>The host Javascript listens to the <code>message</code> event</p>
<pre><code>window.addEventListener('message', function(event){
    var fn = window; 
    var data = JSON.parse(event.data);
    var namespaced = (data['f'] || "").split('.');
    for (var i in namespaced) { 
        fn = fn[namespaced[i]];
    }
    if (typoe(fn) === 'function') {
        fn(data.params);    
    }
});
</code></pre>
<p>The host also sets up a namespace and a function to be called.</p>
<pre><code>window.example = window.example || {};

example.hello = function(){ … }   
</code></pre>
<p>When the iframe has loaded, it sends a ready message to the host</p>
<pre><code>$(document).ready(function(){
    var data = JSON.strinify({f: 'example.hello'});
    parent.postMessage(data, referer); // referer set by server from the request param for the iframe
});
</code></pre>
<p>The host from the script loaded in the bookmarket has the <code>example.hello</code> function and it&#8217;s run. This in turn replies to the iframe.</p>
<pre><code>var example.hello = function(){
    var iframe = document.getElementById('example_iframe');
    var data = JSON.stringify({f: 'example.world'})
    iframe.contentWindow.postMessage(data, 'example.com');
};
</code></pre>
<p>The iframe has an event listener which is the same code as the host, and runs the function <code>example.world</code></p>
<pre><code>var example.world = function(){
    // hello, world
};
</code></pre>
<h2>Wrapping up</h2>
<p>This has shown some of the techniques for a &#8216;hello, world&#8217; bookmark with two way communication between host and iframe that uses Javascript namespaces. This was enough to get our application off the ground as the two way communication acted as a solid base to build upon.</p>
<p>The post <a href="http://pivotallabs.com/to-build-a-bookmarklet/">To build a bookmarklet</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/to-build-a-bookmarklet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The passing of time, and all of its crimes.</title>
		<link>http://pivotallabs.com/the-passing-of-time-and-all-of-its-crimes/</link>
		<comments>http://pivotallabs.com/the-passing-of-time-and-all-of-its-crimes/#comments</comments>
		<pubDate>Mon, 17 Jun 2013 00:08:05 +0000</pubDate>
		<dc:creator>Andrew Bruce</dc:creator>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[bloggerdome]]></category>
		<category><![CDATA[bugs]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[time]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20279</guid>
		<description><![CDATA[<p>Programmers are constantly implementing time-related features, and accidentally including time-related bugs. I&#8217;m one of those programmers, and I would like to reduce the number of time-related bugs that I write. Some of them are small mistakes: time zone issues arise when running a test suite on a machine in a different time zone. These bugs are often fixed with consistent use of the time zone feature of a given time library. Others are more sinister, and lurk deep within the design of a system. They manifest in places where it&#8217;s tricky to get the system into a certain state because it is so heavily dependent on the current time. I propose that designing for the ability to set the current time from the outside of the system reduces the prevalence of timing related bugs, and has the happy accident of making code more reusable and testable. How testing exposes this&#8230;</p><p>The post <a href="http://pivotallabs.com/the-passing-of-time-and-all-of-its-crimes/">The passing of time, and all of its crimes.</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>Programmers are constantly implementing time-related features, and accidentally including time-related bugs. I&#8217;m one of those programmers, and I would like to reduce the number of time-related bugs that I write. Some of them are small mistakes: time zone issues arise when running a test suite on a machine in a different time zone. These bugs are often fixed with consistent use of the time zone feature of a given time library. Others are more sinister, and lurk deep within the design of a system. They manifest in places where it&#8217;s tricky to get the system into a certain state because it is so heavily dependent on the current time. I propose that designing for the ability to set the current time from the outside of the system reduces the prevalence of timing related bugs, and has the happy accident of making code more reusable and testable.</p>
<h2>How testing exposes this problem</h2>
<p>Testing has many forms in the world of software. There are automated acceptance tests, unit tests, functional tests, enemy tests and so on. There are also tests carried out by humans. Sometimes referred to as &#8216;click testing&#8217; or Quality Assurance, this kind of testing is an essential part of the process of delivering working software. At Pivotal Labs, it&#8217;s usually the Product Manager who has the final say about whether a feature is complete, or a bug is fixed. In order to evaluate whether a feature is ready, the PM exercises the area of the application in question, using the interface that a customer or stakeholder has been provided with.</p>
<p>When testing software with a mouse and keyboard becomes difficult, however, it often doesn&#8217;t get done. When it doesn&#8217;t get done, bugs introduced by diligent programmers, who test-drive their code, are missed and end up making their way into production.</p>
<p>After a few cycles of missing bugs like this, a team will look for ways to ease the pain of click testing their app. The programmers on the team might come up with clever, easy-to-implement solutions to this problem:</p>
<ul>
<li>&#8220;We can manipulate the Time library to give us the time we want&#8221;</li>
<li>&#8220;We can change all of the data for a given account to pretend that it was created in the past&#8221;</li>
</ul>
<p>When these sorts of techniques dig in, new problems arise. In the former case, you can end up with code that works when the fake Time library is used, but not when the real one is used. In the latter, you are committed to a maintenance chore: when a timestamp field is added, it needs to change along with the rest, and when the code that changes those fields gets out of sync with how things really change over time, more bugs arise. It becomes difficult to tell which bugs are genuine and which are a consequence of artificially shifting time data.</p>
<p>It&#8217;s usually programmers who propose the above solutions. We often think in low-level terms like libraries and direct data manipulation. From a Product Manager&#8217;s perspective, however, what&#8217;s really needed is a design change. One could imagine the user story presented to the team like this:</p>
<p>As a Product Manager<br />
I want to travel in time<br />
So that I can test, for example, that an account gets billed each month</p>
<p>Time travel sounds like science fiction. How could a user of your system possibly travel in time? It turns out that there are low-level solutions to this. For example, Timecop, which <a href="https://github.com/travisjeffery/timecop/commit/6942d0eed940ea9a4e06d4dd9658f97bd7c14c8b">many</a> <a href="https://github.com/travisjeffery/timecop/commit/7c41d86343225ccb9ccf58701424674d9f0f851b">of</a> <a href="https://github.com/travisjeffery/timecop/commit/f105e15482fa2629693aee95d400c6428025b788">us</a> at Pivotal have contributed to. If depending on the passing of time is your addiction, then Timecop is enabling you. It lets you easily manipulate time, usually for automated testing purposes. For example:</p>
<pre>
<code class="language-ruby">Timecop.freeze(1.month.from_now) do
  future_time = Time.now
  sleep 10
  future_time == Time.now # this is true
end
</code>
</pre>
<p>Here we&#8217;ve frozen time to pretend that it&#8217;s one month in the future. I can imagine some cases where this would be useful (not least in existing systems that are infected with code coupled to the current time), but in a lot of cases this is just wrong. Under what circumstance do you actually expect your code to be frozen in time? What are the consequences of testing code under these conditions?</p>
<p>Perhaps most importantly to the topic of this post, Timecop lets you forget about managing time at the unit level, and doesn&#8217;t encourage you to build time controls into your application.</p>
<p>I think there are better ways to get a grip on time that we should all consider before reaching for the magic wand. Let&#8217;s look at some real-world problems that can occur and then look at ways of building time control into an app&#8217;s design.</p>
<h2>Examining the moment</h2>
<p>Let&#8217;s think about the properties of the current time:</p>
<ul>
<li>There is only one current time, unless you&#8217;re modelling multiple realities e.g. storylines about time travel.</li>
<li>Its value is always changing.</li>
<li>Everything is potentially affected by it.</li>
</ul>
<p>So, the current time is a global, constantly mutating singleton. We know that the presence of global singletons is undesirable, because they are polluting. We also know that mutation ought to be contained, because mutable state makes our programs less predictable and harder to reason about. If a function deals with mutable state, then it might have different results each time it is called, even when it apparently has the same inputs.</p>
<p>Let&#8217;s look at a timing bug that can result from the fact that the current time has these undesirable properties:</p>
<pre>
<code class="language-ruby">policy = Policy.find(1)

if policy.current_state == :active
  notify_customer("You are still insured!")
end
# more code goes here
if policy.current_state == :inactive
  notify_customer("You are not insured. Hope you weren't planning on driving anywhere today.")
end
</code>
</pre>
<p>Imagine that the above code is within a web request. The request comes in at a certain time, and the customer wants to know whether their insurance policy is current. The code above is deep in the guts of a model somewhere, and gets called after the customer has been authenticated, their request has been authorized, and their account record has been pulled out of the database. Now it&#8217;s time to see what the state of the policy is, so we use a method someone wrote (current_state) that fetches the current time and returns a state based on whether the policy&#8217;s end date was before or after that time.</p>
<p>The customer sees this on their screen:</p>
<pre>
You are still insured!
You are not insured. Hope you weren't planning on driving anywhere today.
</pre>
<p>The policy could potentially be active on one line and inactive the next. This kind of bug gets worse when one line makes an external call if the object were in one state, and the next makes a conflicting call if it were in another.</p>
<p>I recently ran into a real bug similar to this on my current project, which was caught when an acceptance test I was writing would fail on one run and pass on the next. The temporary workaround was to memoize the method that checked the current state (current_state above). Unfortunately, this introduced even more mutable state, because memoization requires changing the state of an instance variable. The next programmer might wonder why fetching the current state works the first time he asks, but stays the same with consecutive calls.</p>
<h2>current_nothing</h2>
<p>The current_state method is guilty here. But what of? It has a hidden input, which is the current time. It&#8217;s not explicit, and that&#8217;s where the confusion lies. It wouldn&#8217;t make sense to have a method called current_something and have it take the time as an argument, because the prefix &#8220;current_&#8221; implies that it&#8217;s supposed to know what the current state is.</p>
<p>The internal functions of a program shouldn&#8217;t know this stuff. In most web apps, a request is made at a certain point in time, but it&#8217;s not important that the request takes some time. With most scheduled jobs, the job is run at a certain time, but it&#8217;s not important that the job takes some time (or if it is, it&#8217;s stored as metadata).</p>
<p>A name less prone to attracting this kind of bug might be state_as_of(time). If we force ourselves to pass the time as a parameter to all of our low-level functions, then we can:</p>
<ol>
<li>More easily unit test the basic correctness of the method without resorting to stubbing out the time with Timecop.</li>
<li>Force out a decision to be made about what moment the lower-level methods should be operating on. Ideally the control would move as high as possible: to the controller level, or in the case of jobs, to the job itself, or to an environment variable.</li>
</ol>
<h2>A word about scheduling</h2>
<p>Scheduled jobs are often concerned with when they think they&#8217;re being run, but a PM doesn&#8217;t want to wait for a month to see if, for example, the billing system is working. It&#8217;s important to give control over when a job thinks it&#8217;s being run to the PM or other person evaluating whether a system works. This might mean dropping your out-of-the-box scheduling interface for the purposes of feature acceptance.</p>
<p><a href="https://github.com/bvandenbos/resque-scheduler">Resque-scheduler</a> has become very popular amongst developers as it&#8217;s easy to install and provides a cron-like syntax for declaring when jobs are run. It also provides a GUI for triggering scheduled jobs immediately. Unfortunately, there&#8217;s no way to set parameters for the jobs, so the time can&#8217;t be set. If you choose to heed the advice in this post and parameterize time, you&#8217;ll need to provide your own interface for passing the current time into the system. This is a good idea anyway. See <a href="http://growing-object-oriented-software.com/">GOOS</a> for a good treatment of externalizing event sources, which goes even further than the suggestions in this post in many ways.</p>
<p>Making time a parameter to your jobs can often make the jobs more reusable. For example, I might want to invalidate all sessions in a particular time range because there was a system fault at those times.</p>
<h2>A word about external dependencies</h2>
<p>What happens if your external dependencies are dependent on the current time? Well, you&#8217;re going to have problems with that no matter how much control you build into your system. I would argue that the services should be wrapped, and the wrappers should allow the time to be passed in to fake responses if necessary. The acceptance (as in story acceptance in Pivotal Tracker) of your system doesn&#8217;t have to depend on the state of the other systems.</p>
<h2>A word about customer-facing status pages</h2>
<p>What if your customer needs to be shown what&#8217;s happening right now?<br />
I think the trick here is to depend on the order of time, and not the passing of time. To move into the future, we should be reacting to events by adding data, not mutating it. A database can easily figure out what the latest order is, or what the latest billing cycle is. It doesn&#8217;t have to be a function of the current time.</p>
<p>If, however, it&#8217;s just too difficult to implement the functionality without checking the current time, it could be argued that the current time be a parameter passed in through the browser, available only in certain testing environments. I would resist this as far as possible, but think that it would be a preferable solution to mutating the state of the database.</p>
<p>The post <a href="http://pivotallabs.com/the-passing-of-time-and-all-of-its-crimes/">The passing of time, and all of its crimes.</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/the-passing-of-time-and-all-of-its-crimes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Everyday Git Commands in RubyMine</title>
		<link>http://pivotallabs.com/everyday-git-commands-in-rubymine/</link>
		<comments>http://pivotallabs.com/everyday-git-commands-in-rubymine/#comments</comments>
		<pubDate>Sun, 16 Jun 2013 20:19:34 +0000</pubDate>
		<dc:creator>Jared Carroll</dc:creator>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[mouse-free development]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[rubymine]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20284</guid>
		<description><![CDATA[<p>As a long-time command-line Git user, I was hesitant to adopt RubyMine&#8217;s version control tools. But I decided to give them a try, and I&#8217;m glad I did. RubyMine&#8217;s version control tools make common Git commands more accessible and easier to execute. The addition of a GUI is great for tasks such as diffing a file, or viewing commit logs. In this post, we&#8217;ll look at performing everyday Git commands in RubyMine on OS X. git-diff You can view a diff of all your changes from the Changes tool window. Press command + 9 to open the Changes tool window. Then press command + D to view a diff of all your changes. You can diff a single file by selecting &#8220;Compare with the Same Repository Version&#8221; from the VCS Operations popup. Press control + V to open the VCS Operations popup. git-commit Press command + K to commit changes.&#8230;</p><p>The post <a href="http://pivotallabs.com/everyday-git-commands-in-rubymine/">Everyday Git Commands in RubyMine</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>
As a long-time command-line Git user, I was hesitant to adopt RubyMine&#8217;s version control tools. But I decided to give them a try, and I&#8217;m glad I did. RubyMine&#8217;s version control tools make common Git commands more accessible and easier to execute. The addition of a GUI is great for tasks such as diffing a file, or viewing commit logs.  In this post, we&#8217;ll look at performing everyday Git commands in RubyMine on <a href="http://www.jetbrains.com/ruby/docs/RubyMine_ReferenceCard_Mac.pdf">OS X</a>.
</p>
<h2>git-diff</h2>
<p>
You can view a diff of all your changes from the Changes tool window.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/changes-tool-window.png?b966ad" alt="changes-tool-window" />
</p>
<p>
Press <code>command + 9</code> to open the Changes tool window. Then press <code>command + D</code> to view a diff of all your changes.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/view-diff.png?b966ad" alt="view-diff" />
</p>
<p>
You can diff a single file by selecting &#8220;Compare with the Same Repository Version&#8221; from the VCS Operations popup. Press <code>control + V</code> to open the VCS Operations popup.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/compare-vcs-operations-popup.png?b966ad" alt="compare-vcs-operations-popup" />
</p>
<h2>git-commit</h2>
<p>
Press <code>command + K</code> to commit changes.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/commit-changes.png?b966ad" alt="commit-changes" />
</p>
<h2>git-push</h2>
<p>
Select &#8220;Push&#8230;&#8221; from the VCS Operations popup, <code>control + V</code>, to push your local changes.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/push-vcs-operations-popup.png?b966ad" alt="push-vcs-operations-popup" />
</p>
<h2>git-pull</h2>
<p>
Press <code>command + T</code> to pull in the latest changes.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/update-project.png?b966ad" alt="update-project" />
</p>
<h2>git-log</h2>
<p>
To view the Git log, open the Changes tool window, <code>command + 9</code>, then navigate to the Log tab with <code>command + shift + ]</code>.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/git-log-changes-tool-window.png?b966ad" alt="git-log-changes-tool-window" />
</p>
<p>
To see the log of a single file, select &#8220;Show History&#8221; from the VCS Operations popup, <code>control + V</code>.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/show-history-vcs-operations-popup.png?b966ad" alt="show-history-vcs-operations-popup" />
</p>
<p>
This will open the log in the Version Control tool window.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/show-history.png?b966ad" alt="show-history" />
</p>
<h2>git-checkout</h2>
<p>
Revert changes by selecting &#8220;Revert&#8221; from the VCS Operations popup, <code>control + V</code>.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/revert-vcs-operations-popup.png?b966ad" alt="revert-vcs-operations-popup" />
</p>
<h2>git-blame</h2>
<p>
Determine who changed a file by selecting &#8220;Annotate&#8221; from the VCS Operations popup, <code>control + V</code>.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/annotate-vcs-operations-popup.png?b966ad" alt="annotate-vcs-operations-popup" />
</p>
<p>
The committers will be displayed to the left of the editor gutter.
</p>
<p>
<img src="http://pivotallabs.com/wordpress/wp-content/uploads/2013/06/annotate.png?b966ad" alt="annotate" />
</p>
<h2>Don&#8217;t Abandon the Command-line</h2>
<p>
In this post, I focused on the most commonly used Git commands. RubyMine also includes support for more powerful Git commands, such as <code>git-reset</code> and <code>git-rebase</code>. However, I find their RubyMine GUI-based implementations slow and clumsy. As much as I want to stay in RubyMine, I find the best version control strategy is to use RubyMine for common Git commands, but turn to the command-line for the hard stuff.</p>
<p>The post <a href="http://pivotallabs.com/everyday-git-commands-in-rubymine/">Everyday Git Commands in RubyMine</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/everyday-git-commands-in-rubymine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ember.js and SoundManager2</title>
		<link>http://pivotallabs.com/ember-js-and-soundmanager2/</link>
		<comments>http://pivotallabs.com/ember-js-and-soundmanager2/#comments</comments>
		<pubDate>Sun, 16 Jun 2013 17:29:37 +0000</pubDate>
		<dc:creator>Luan Santos</dc:creator>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[audio]]></category>
		<category><![CDATA[bloggerdome]]></category>
		<category><![CDATA[ember.js]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[soundmanager]]></category>

		<guid isPermaLink="false">http://pivotallabs.com/?p=20268</guid>
		<description><![CDATA[<p>Continuing the experimentation with cool libraries and ember this time I’ll use SoundManager2, a really useful sound playing library for HTML5 and/or Flash that is compatible with most browsers out there. It is not very hard to use and it has a pretty decent documentation, what I’ll show is a very simple usage of it that I plan to improve in the future, but this should give an idea on how to start at least. My app has a Song model that contains a url property, there is a ‘songs’ route that lists the songs and a ‘song’ route that shows the player for a given song. Let’s start by including SoundManager2 into our app, grab your copy from their website, the downloaded zipfile will have several folders, look for soundmanager2.js in the script folder and soundmanager2_debug.swf in the swf folder. You’ll want to change this to the nodebug version&#8230;</p><p>The post <a href="http://pivotallabs.com/ember-js-and-soundmanager2/">Ember.js and SoundManager2</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>Continuing the experimentation with cool libraries and ember this time I’ll use <a href="”http://www.schillmania.com/projects/soundmanager2/”">SoundManager2</a>, a really useful sound playing library for HTML5 and/or Flash that is compatible with most browsers out there.</p>
<p>It is not very hard to use and it has a pretty decent documentation, what I’ll show is a very simple usage of it that I plan to improve in the future, but this should give an idea on how to start at least.</p>
<p>My app has a <code>Song</code> model that contains a <code>url</code> property, there is a ‘songs’ route that lists the songs and a ‘song’ route that shows the player for a given song.</p>
<p>Let’s start by including SoundManager2 into our app, grab your copy from their website, the downloaded zipfile will have several folders, look for <code>soundmanager2.js</code> in the <code>script</code> folder and <code>soundmanager2_debug.swf</code> in the swf folder. You’ll want to change this to the nodebug version when you’re going production.</p>
<p>Once we did that we need to initialize soundmanager with our app. We do that by adding an initializer:</p>
<pre><code>App.initializer({
  name: "soundmanager",
  initialize: function() {
    soundManager.setup({
      url: '/swf'
    });
  }
});</code></pre>
<p>Note the ‘/swf’ path there, that’s where you put the swf file, update accordingly. This initializer will setup soundmanager with all the default options, you can override them by adding more properties to the setup function call. Please refer to the <a href="http://www.schillmania.com/projects/soundmanager2/doc/">documentation</a>.</p>
<p>Alright, now that we have everything in place we can use soundmanager to manage our sounds. I said that I have a route for each ‘song’ so let’s start by adding the template for that route.</p>
<pre><code>&lt;script type="text/x-handlebars" id="song"&gt;
  &lt;button class="btn" {{action 'playPause'}}&gt;{{playPauseLink}}&lt;/button&gt;
  &lt;button class="btn" {{action 'stop'}} {{bindAttr disabled="unstarted"}}&gt;Stop&lt;/button&gt;
&lt;/script&gt;</code></pre>
<p>This template has some stuff in it, let’s start by looking at the ‘playPause’ button, it’s content is a variable ‘playPauseLink’, we expect that to be either “Play” or “Pause” depending on the current state of the player, and it’s action is ‘playPause’ which will toggle the two.</p>
<p>Let’s take a look at ‘playPauseLink’:</p>
<pre><code>App.SongController = Ember.ObjectController.extend({
  // …
  playPauseLink: function() {
    if (this.get('playing')) {
      return 'Pause';
    } else {
      return 'Play'
    }
  }.property('playing'),
  // …
});</code></pre>
<p>Our controller have a property ‘playing’ which is a boolean for whether the song is playing or not, we use that to compute the play/pause link text with a binding, so it will stay up to date automatically. Now let’s see the playPause action:</p>
<pre><code>App.SongController = Ember.ObjectController.extend({
  // ...
  playPause: function() {
    if (this.get('playing')) {
      this.pause();
    } else {
      this.play();
    }
  },

  play: function() {
    var sound = this.get('sound');

    if (this.get('unstarted')) {
      sound.play();
      this.set('started', true);
    } else {
      sound.resume();
    }

    this.set('playing', true);
  },

  pause: function() {
    this.get('sound').pause();
    this.set('playing', false);
  },
  // …</code></pre>
<p>Now I’m showing you 3 methods, one is the actual action ‘playPause’, that will call either play or pause depending on the current state of the player, play and pause will set the ‘playing’ state accordingly. Play will either ‘play’ or ‘resume’ depending on whether the player has started or not, we use the property ‘started’ and it’s counterpart ‘unstarted’ for that purpose.</p>
<p>That’s all great but it will do nothing if we don’t load the sound first, we have to do that after soundmanager is ready and the template is inserted, let’s do that in our ‘SongView’ on the ‘didInsertElement’ callback.</p>
<pre><code>App.SongView = Ember.View.extend({
  didInsertElement: function() {
    var self  = this;

    soundManager.onready(function() {
      self.get('controller').send('loadSound');
    });
  }
});</code></pre>
<p>Note that we’re calling the ‘loadSound’ method in our controller once soundmanager is ready:</p>
<pre><code>App.SongController = Ember.ObjectController.extend({
  // ...
  loadSound: function() {
    var self = this;
    var sound = soundManager.createSound({
      url: this.get('url'),
      onfinish: function() { self.finish(); }
    });

    this.set('sound', sound);
  },</code></pre>
<p>Loading the sound is as simple as following the soundmanager’s documentation, create a sound passing in the ‘url’ property from our model. We set the ‘onfinish’ callback to reset the player once the sound is over. We’re also missing the ‘stop’ functionality that we have on the template:</p>
<pre><code>App.SongController = Ember.ObjectController.extend({
  // ...
  finish: function() {
    this.set('playing', false);
    this.set('started', false);
  },

  stop: function() {
    this.get('sound').stop();
    this.finish();
  },</code></pre>
<p>‘finish’ is just resetting the states, stop is calling stop on our sound object and then resetting the state by calling finish.</p>
<p>That is about the simplest play/pause/stop player I could think of using soundmanager, I published the full code for this simple implementaiton on this <a href="https://gist.github.com/luan/5792720">Gist</a>. It has a little bit more to it like position/duration but it’s pretty much what I wrote above.</p>
<p>&nbsp;</p>
<p>Library versions used in the post:</p>
<ul>
<li>Ember.js: 1.0.0-rc.5</li>
<li>Handlebars: 1.0.0-rc.4</li>
<li>Ember Data: 0.13</li>
<li>jQuery: 1.9.1</li>
<li>SoundManager2: 2.97a.20130512</li>
</ul>
<p>The post <a href="http://pivotallabs.com/ember-js-and-soundmanager2/">Ember.js and SoundManager2</a> appeared first on <a href="http://pivotallabs.com">Pivotal Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://pivotallabs.com/ember-js-and-soundmanager2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic (Feed is rejected)
Page Caching using apc
Database Caching 3/5 queries in 0.002 seconds using apc
Object Caching 1158/1164 objects using apc

 Served from: pivotallabs.com @ 2013-06-18 18:32:13 by W3 Total Cache -->