CINXE.COM
dev tools | code.flickr.com
<!DOCTYPE html> <!--[if IE 6]> <html id="ie6" lang="en"> <![endif]--> <!--[if IE 7]> <html id="ie7" lang="en"> <![endif]--> <!--[if IE 8]> <html id="ie8" lang="en"> <![endif]--> <!--[if !(IE 6) | !(IE 7) | !(IE 8) ]><!--> <html lang="en"> <!--<![endif]--> <!-- generated 283 seconds ago generated in 0.231 seconds served from batcache in 0.003 seconds expires in 17 seconds --> <head><script type="text/javascript" src="https://web-static.archive.org/_static/js/bundle-playback.js?v=7YQSqjSh" charset="utf-8"></script> <script type="text/javascript" src="https://web-static.archive.org/_static/js/wombat.js?v=txqj7nKC" charset="utf-8"></script> <script>window.RufflePlayer=window.RufflePlayer||{};window.RufflePlayer.config={"autoplay":"on","unmuteOverlay":"hidden"};</script> <script type="text/javascript" src="https://web-static.archive.org/_static/js/ruffle/ruffle.js"></script> <script type="text/javascript"> __wm.init("https://web.archive.org/web"); __wm.wombat("http://code.flickr.net/tag/dev-tools/","20130906231042","https://web.archive.org/","web","https://web-static.archive.org/_static/", "1378509042"); </script> <link rel="stylesheet" type="text/css" href="https://web-static.archive.org/_static/css/banner-styles.css?v=p7PEIJWi" /> <link rel="stylesheet" type="text/css" href="https://web-static.archive.org/_static/css/iconochive.css?v=3PDvdIFv" /> <!-- End Wayback Rewrite JS Include --> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width"/> <title>dev tools | code.flickr.com</title> <link rel="profile" href="http://gmpg.org/xfn/11"/> <link rel="stylesheet" type="text/css" media="all" href="https://web.archive.org/web/20130906231042cs_/http://s2.wp.com/wp-content/themes/vip/flickr-code/style.css?m=1345671377g"/> <link rel="pingback" href="http://code.flickr.net/xmlrpc.php"/> <!--[if lt IE 9]> <script src="http://s2.wp.com/wp-content/themes/pub/twentyeleven/js/html5.js?m=1354160568g" type="text/javascript"></script> <![endif]--> <script src="https://web.archive.org/web/20130906231042js_/http://r-login.wordpress.com/remote-login.php?action=js&host=code.flickr.net&id=39034126&t=1378508758&back=code.flickr.net%2Ftag%2Fdev-tools%2F" type="text/javascript"></script> <script type="text/javascript"> /* <![CDATA[ */ if ( 'function' === typeof WPRemoteLogin ) { document.cookie = "wordpress_test_cookie=test; path=/"; if ( document.cookie.match( /(;|^)\s*wordpress_test_cookie\=/ ) ) { WPRemoteLogin(); } } /* ]]> */ </script> <link rel="alternate" type="application/rss+xml" title="code.flickr.com 禄 Feed" href="https://web.archive.org/web/20130906231042/http://code.flickr.net/feed/"/> <link rel="alternate" type="application/rss+xml" title="code.flickr.com 禄 Comments Feed" href="https://web.archive.org/web/20130906231042/http://code.flickr.net/comments/feed/"/> <link rel="alternate" type="application/rss+xml" title="code.flickr.com 禄 dev tools Tag Feed" href="https://web.archive.org/web/20130906231042/http://code.flickr.net/tag/dev-tools/feed/"/> <script type="text/javascript"> /* <![CDATA[ */ function addLoadEvent(func){var oldonload=window.onload;if(typeof window.onload!='function'){window.onload=func;}else{window.onload=function(){oldonload();func();}}} /* ]]> */ </script> <link rel="stylesheet" id="all-css-0" href="https://web.archive.org/web/20130906231042cs_/http://s2.wp.com/_static/??-eJydjt0OgjAMRl/IWQkqV8ZnGaOwsW5rWAfh7UUTr/yJ8ar5+p2cFhZWJkXBKBCKYiqDixnIecwworA2Xj3S3uS8g/c4pyyqJ+0myLISvrBiMWxCLi3Isi1WJJwxfqdnx9CTM37amg7/UauFTQq/vm715OLwnJ8u2SMMlFpNd+AaLlXdNIe6Pp2r8QYWmXzm" type="text/css" media="all"/> <script type="text/javascript" src="https://web.archive.org/web/20130906231042js_/http://s1.wp.com/_static/??-eJyFzdsKwjAMgOEXsisesHghPkutcSSuaW3SDX16O1BQEHYVSD7y2ymbkFiB1ZLYmM44gKkCxfdtZ5CvqSNZ2eaQw1AvIDOke4XyeI9FYCL2xSt0EfmDv6o5iUYQack/198U8ogwLTICzT7cTAHB5/z1FI/rrXObvTu4Hb0AKYVb3w=="></script> <link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://flickrcode.wordpress.com/xmlrpc.php?rsd"/> <link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://flickrcode.wordpress.com/wp-includes/wlwmanifest.xml"/> <meta name="generator" content="WordPress.com"/> <link rel="shortcut icon" type="image/x-icon" href="https://web.archive.org/web/20130906231042im_/http://1.gravatar.com/blavatar/341946154e8a7e5497473810e7ef560c?s=16" sizes="16x16"/> <link rel="icon" type="image/x-icon" href="https://web.archive.org/web/20130906231042im_/http://1.gravatar.com/blavatar/341946154e8a7e5497473810e7ef560c?s=16" sizes="16x16"/> <link rel="apple-touch-icon-precomposed" href="https://web.archive.org/web/20130906231042im_/http://0.gravatar.com/blavatar/8b1d73fba9c0d02a3e78929d8cecfd82?s=114"/> <link rel="openid.server" href="http://flickrcode.wordpress.com/?openidserver=1"/> <link rel="openid.delegate" href="http://flickrcode.wordpress.com/"/> <link rel="search" type="application/opensearchdescription+xml" href="https://web.archive.org/web/20130906231042/http://code.flickr.net/osd.xml" title="code.flickr.com"/> <link rel="search" type="application/opensearchdescription+xml" href="https://web.archive.org/web/20130906231042/http://wordpress.com/opensearch.xml" title="WordPress.com"/> <style> /* <![CDATA[ */ /* Block: reblog */ .reblog-from img { margin: 0 10px 0 0; vertical-align: middle; padding: 0; border: 0; } .reblogger-note img.avatar { float: left; padding: 0; border: 0; } .reblogger-note-content { margin: 0 0 20px; } .reblog-post .wpcom-enhanced-excerpt-content { border-left: 3px solid #eee; padding-left: 15px; } .reblog-post ul.thumb-list { display: block; list-style: none; margin: 2px 0; padding: 0; clear: both; } .reblog-post ul.thumb-list li { display: inline; margin: 0; padding: 0 1px; border: 0; } .reblog-post ul.thumb-list li a { margin: 0; padding: 0; border: 0; } .reblog-post ul.thumb-list li img { margin: 0; padding: 0; border: 0; } .reblog-post .wpcom-enhanced-excerpt { clear: both; } .reblog-post .wpcom-enhanced-excerpt address, .reblog-post .wpcom-enhanced-excerpt li, .reblog-post .wpcom-enhanced-excerpt h1, .reblog-post .wpcom-enhanced-excerpt h2, .reblog-post .wpcom-enhanced-excerpt h3, .reblog-post .wpcom-enhanced-excerpt h4, .reblog-post .wpcom-enhanced-excerpt h5, .reblog-post .wpcom-enhanced-excerpt h6, .reblog-post .wpcom-enhanced-excerpt p { font-size: 100% !important; } .reblog-post .wpcom-enhanced-excerpt blockquote, .reblog-post .wpcom-enhanced-excerpt pre, .reblog-post .wpcom-enhanced-excerpt code, .reblog-post .wpcom-enhanced-excerpt q { font-size: 98% !important; } /* ]]> */ </style> <meta name="application-name" content="code.flickr.com"/><meta name="msapplication-window" content="width=device-width;height=device-height"/><meta name="msapplication-task" content="name=Subscribe;action-uri=http://code.flickr.net/feed/;icon-uri=http://1.gravatar.com/blavatar/341946154e8a7e5497473810e7ef560c?s=16"/> <style type="text/css" id="twentyeleven-header-css"> #site-title, #site-description { position: absolute !important; clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ clip: rect(1px, 1px, 1px, 1px); } </style> <style id="syntaxhighlighteranchor"></style> <link rel="stylesheet" id="custom-css-css" type="text/css" href="https://web.archive.org/web/20130906231042cs_/http://code.flickr.net/?custom-css=1&csblog=2DMyG&cscache=6&csrev=103"/> </head> <body class="archive tag tag-dev-tools tag-175262 typekit-enabled two-column right-sidebar mp6 highlander-enabled highlander-light"> <div id="page" class="hfeed"> <header id="branding" role="banner"> <hgroup> <h1 id="site-title"><span><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/" title="code.flickr.com" rel="home">code.flickr.com</a></span></h1> <h2 id="site-description"></h2> </hgroup> <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/"> <img src="https://web.archive.org/web/20130906231042im_/http://flickrcode.files.wordpress.com/2012/09/code-flickr-com-drawn-header-grey-large.png" width="1000" height="157" alt=""/> </a> <div class="only-search with-image"> <form method="get" id="searchform" action="https://web.archive.org/web/20130906231042/http://code.flickr.net/"> <label for="s" class="assistive-text">Search</label> <input type="text" class="field" name="s" id="s" placeholder="Search"/> <input type="submit" class="submit" name="submit" id="searchsubmit" value="Search"/> </form> </div> <nav id="access" role="navigation"> <h3 class="assistive-text">Main menu</h3> <div class="skip-link"><a class="assistive-text" href="#content" title="Skip to primary content">Skip to primary content</a></div> <div class="skip-link"><a class="assistive-text" href="#secondary" title="Skip to secondary content">Skip to secondary content</a></div> <div class="menu-menu-container"><ul id="menu-menu" class="menu"><li id="menu-item-2084" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-2084"><a href="https://web.archive.org/web/20130906231042/http://www.flickr.com/">Flickr</a></li> <li id="menu-item-2085" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-2085"><a href="https://web.archive.org/web/20130906231042/http://blog.flickr.net/">Flickr Blog</a></li> <li id="menu-item-2250" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-2250"><a href="https://web.archive.org/web/20130906231042/http://twitter.com/flickr">@flickr</a></li> <li id="menu-item-2086" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-2086"><a href="https://web.archive.org/web/20130906231042/http://twitter.com/flickrapi">@flickrapi</a></li> <li id="menu-item-2087" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-2087"><a href="https://web.archive.org/web/20130906231042/http://developer.flickr.com/">Developer Guidelines</a></li> <li id="menu-item-2088" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-2088"><a href="https://web.archive.org/web/20130906231042/http://www.flickr.com/services/api/">API</a></li> <li id="menu-item-2089" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-2089"><a href="https://web.archive.org/web/20130906231042/http://www.flickr.com/jobs/">Jobs</a></li> </ul></div> </nav><!-- #access --> </header><!-- #branding --> <div id="main"> <section id="primary"> <div id="content" role="main"> <header class="page-header"> <h1 class="page-title">Tag Archives: <span>dev tools</span></h1> </header> <article id="post-2416" class="post-2416 post type-post status-publish format-standard hentry category-performance tag-chrome tag-compositing tag-dev-tools tag-gpu tag-hardware-acceleration tag-painting tag-performance"> <header class="entry-header"> <h1 class="entry-title"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2013/06/04/adventures-in-jank-busting-parallax-performance-and-the-new-flickr-home-page/" rel="bookmark">Adventures in Jank Busting: Parallax, performance, and the new Flickr Home Page</a></h1> <div class="entry-meta"> <span class="sep">Posted on </span><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2013/06/04/adventures-in-jank-busting-parallax-performance-and-the-new-flickr-home-page/" title="5:25 pm" rel="bookmark"><time class="entry-date" datetime="2013-06-04T17:25:48+00:00">June 4, 2013</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="https://web.archive.org/web/20130906231042/http://code.flickr.net/author/scottschiller/" title="View all posts by scottschiller" rel="author">scottschiller</a></span></span> </div><!-- .entry-meta --> </header><!-- .entry-header --> <div class="entry-content"> <p class="aside">tl;dr version: <code>transform3d()</code> is your friend, but use sparingly. Chrome Dev Tools are awesome.</p> <h2>What’s old is new again: Stealing from the arcade</h2> <p>Back in 1985, games like Super Mario Bros. popularized the effect of horizontal parallax scrolling – a technique wherein the background moves at a slower speed relative to the foreground, giving the impression of depth. In 2013, the web is seeing a trend of vertical parallax effects as developers look to make pages feel more interactive and responsive. Your author’s $0.25, for the record, is that we’ll continue to see arcade and demoscene-era effects being ported over to the mainstream web in creative ways as client-side performance improves.</p> <p>While the effect can be aesthetically pleasing when executed correctly, parallax motion tends to be expensive to render – and when performance is lacking, the user’s impression of your site may follow suit.</p> <p>Vertical parallaxing is pretty straightforward in behaviour: For every Y pixels of vertical axis scrolling, move an absolutely-positioned image in the same direction at scale. There are some additional considerations for the offset of the element on the page and how far it can move, but the implementation remains quite simple.</p> <p>The following are some findings made while working on Flickr’s redesigned signed-out homepage at <a href="https://web.archive.org/web/20130906231042/http://flickr.com/new">flickr.com/new</a>, specifically related to rendering and scrolling performance.</p> <h2>Events and DOM performance</h2> <p>To optimize performance in the browser environment, it’s important to consider the expensive parts of DOM “I/O”. You ideally want a minimal amount of both, particularly since this is work being done during scrolling. Executing JavaScript on scroll is one of the worst ways to interrupt the browser, typically because it’s done to introduce reflow/layout and painting – thus, denying the browser the chance to use GPU/hardware-accelerated scrolling. <code>window.onscroll()</code> can also fire very rapidly on desktops, making way for a veritable flood of expensive scroll → reflow → paint operations if your “paths” are not fast.</p> <p>A typical parallax implementation will hook into <code>window.onscroll()</code>, and will update the <code>backgroundPosition</code> or <code>marginTop</code> of an element with a background image attached in order to make it move. An <code><img></code> could be used here, but backgrounds are convenient because they allow for positioning in relative units, tiling and so on.</p> <p>A minimal parallax example, just the script portion:</p> <pre class="brush: jscript; gutter: false; title: ; notranslate" title=""> window.onscroll = function(e) { var parallax = document.getElementById('parallax-background'); parallax.style.marginTop = (window.scrollY/2) + 'px'; }</pre> <p>This could work for a single element, but quickly breaks down if multiple elements are to be updated. In any case, references to the DOM should be cached for faster look-ups; reading <code>window.scrollY</code> and other DOM attributes can be expensive due to potential to cause layout/reflow themselves, and thus should also be stored in a local variable for each <code>onscroll()</code> event to minimize thrashing.</p> <p>An additional performance consideration: Should all parallax elements always be moved, even those which are outside of the viewport? Quick tests suggested savings were negligible in this case at best. Even if the additional work to determine in-view elements were free, moving only one element did not notably improve performance relative to moving only three at a time. It appears that Webkit’s rendering engine is smart about this, as the only expensive operations seen here involve painting things within the viewport.</p> <p>In any event, using <code>marginTop</code> or <code>backgroundPosition</code> alone will not perform well as neither take advantage of hardware-accelerated compositing.</p> <p>And now, VOIDH (Video Or It Didn’t Happen) of <code>marginTop</code>-based parallax performing terribly:</p> <object type="application/x-shockwave-flash" width="639" height="364" data="https://web.archive.org/web/20130906231042im_/http://www.flickr.com/apps/video/stewart.swf?v=1.161" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"> <param name="flashvars" value="photo_id=8859509880&photo_secret=412e7dafff&flickr_show_info_box=true"></param><param name="movie" value="http://www.flickr.com/apps/video/stewart.swf?v=1.161"></param><param name="bgcolor" value="#000000"></param><param name="allowFullScreen" value="true"></param><param name="wmode" value="opaque"></param><embed type="application/x-shockwave-flash" src="https://web.archive.org/web/20130906231042oe_/http://www.flickr.com/apps/video/stewart.swf?v=1.161" bgcolor="#000000" allowfullscreen="true" flashvars="photo_id=8859509880&photo_secret=412e7dafff&flickr_show_info_box=true" wmode="opaque" height="364" width="639"></embed></object> <p>Look at that: Terrible. Jank city! You can try it for yourself in your browser of choice, via <a href="https://web.archive.org/web/20130906231042/http://www.flickr.com/new/?notransform=1">via ?notransform=1</a>.</p> <h2>Enter the GPU: Hardware Acceleration To The Rescue</h2> <p>Despite caching our DOM references and scroll properties, the cost of drawing all these pixels in software is very high. The trick to performance here is to have the GPU (hardware) take on the job of accelerating the compositing of the expensive bits, which can be done much faster than in software rendering.</p> <p>Elements can be promoted to a “layer” in rendering terms, via CSS transforms like <code>translate3d()</code>. When this and other <code>translateZ()</code>-style properties are applied, the element will then be composited by the GPU, avoiding expensive repaints. In this case, we are interested in having fast-moving parallax backgrounds. Thus, <code>translate3d()</code> can be applied directly to the parallax element.</p> <pre class="brush: jscript; gutter: false; title: ; notranslate" title="">window.onscroll = function(e) { // note: most browsers presently use prefixes: webkitTransform, mozTransform etc. var parallax = document.getElementById('parallax-background'); parallax.style.transform = 'translate3d(0px,' + (window.scrollY/2) + 'px, 0px)'; }</pre> <p>In webkit-based browsers like Safari and Chrome, the results speak for themselves.</p> <object type="application/x-shockwave-flash" width="640" height="448" data="https://web.archive.org/web/20130906231042im_/http://www.flickr.com/apps/video/stewart.swf?v=1.161" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"> <param name="flashvars" value="photo_id=8758952624&photo_secret=f414d2f2fd&flickr_show_info_box=true"></param><param name="movie" value="http://www.flickr.com/apps/video/stewart.swf?v=1.161"></param><param name="bgcolor" value="#000000"></param><param name="allowFullScreen" value="true"></param><param name="wmode" value="opaque"></param><embed type="application/x-shockwave-flash" src="https://web.archive.org/web/20130906231042oe_/http://www.flickr.com/apps/video/stewart.swf?v=1.161" bgcolor="#000000" allowfullscreen="true" flashvars="photo_id=8758952624&photo_secret=f414d2f2fd&flickr_show_info_box=true" wmode="opaque" height="448" width="640"></embed></object> <p>Look, ma! Way less jank! The performance here is comparable to the same page <a href="https://web.archive.org/web/20130906231042/http://www.flickr.com/new/?noparallax=1">with parallax disabled</a> (i.e., regular browser scrolling/drawing.)</p> <p>GPU acceleration sounds like a magic bullet, but it comes at the cost of both video memory and cache. If you create too many layers, you may see rendering problems and even degraded performance – so use them selectively.</p> <p>It’s also worth noting that browser-based hardware acceleration and performance rests on having agreement between the browser, drivers, OS, and hardware. Firefox might be sluggish on one machine, and butter-smooth on another. High-density vs. standard-resolution screens make a big difference in paint cost. All GPUs are made equal, but some GPUs are made more equal than others. The videos and screenshots for this post were made on my work laptop, which may perform quite differently than your hardware. Ultimately, you need to test your work on a variety of devices to see what real-world performance is like – and this is where Chrome’s dev tools come in handy.</p> <h2>Debugging Render Performance</h2> <p>In brief, Chrome’s <a href="https://web.archive.org/web/20130906231042/https://developers.google.com/chrome-developer-tools/">Developer Tools</a> are awesome. Chrome Canary typically has the freshest features in regards to profiling, and Safari also has many of the same. The features most of interest to this entry are the Timeline → Frames view, and the gear icon’s “Show Paint rectangles” and “Show composited layer borders” options.</p> <p class="figure"> <img src="https://web.archive.org/web/20130906231042im_/http://farm3.staticflickr.com/2856/8845899090_59b30986bd_b.jpg" width="1024" height="612" alt=""><br/> <span class="caption"><br/> Timeline → Frames view: Helpful in identifying expensive painting operations.<br/> </span> </p> <p class="figure"> <img src="https://web.archive.org/web/20130906231042im_/http://farm4.staticflickr.com/3828/8858723401_122cff05ec_b.jpg" width="1024" height="612" alt=""><br/> <span class="caption"><br/> Paint rectangles + composited layer borders, AKA “Plaid mode.” Visually identify layers.<br/> </span> </p> <h3>Timeline → Frames view</h3> <p>Timeline’s “Frames” view allows you to see how much time is spent calculating and drawing each frame during runtime, which gives a good idea of rendering performance. To maintain a refresh rate of 60 frames per second, each frame must take no longer than 16 milliseconds to draw. If you have JS doing expensive things during scroll events, this can be particularly challenging.</p> <p>Expensive frames in Flickr’s case stem primarily from occasional decoding of JPEGs and non-cached image resizes, and more frequently, compositing and painting. The less of each that your page requires, the better.</p> <h3>Paint rectangles</h3> <p>It is interesting to see what content is being painted (and re-painted) by the browser, particularly during scroll events. Enabling paint rectangles in Chrome’s dev tools results in red highlights on paint areas. In the ideal case when scrolling, you should see red only around the scrollbar area; in the best scenario, the browser is able to efficiently move the rest of the HTML content in hardware-accelerated fashion, effectively sliding it vertically on the screen without having to perform expensive paint operations. Script-based DOM updates, CSS <code>:hover</code> and transition effects can all cause painting to happen when scrolling, so keep these things in mind as well.</p> <h3>Composited layer borders</h3> <p>As mentioned previously, layers are elements that have been promoted and are to be composited by the GPU, via CSS properties like <code>translate3d()</code>, <code>translateZ()</code> and so on. With layer borders enabled, you can get a visual representation of promoted elements and review whether your CSS is too broad or too specific in creating these layers. The browser itself may also create additional layers based on a number of scenarios such as the presence of child elements, siblings, or elements that overlap an existing layer.</p> <p>Composited borders are shown in brown. Cyan borders indicate a tile, which combines with other tiles to form a larger composited layer.</p> <h2>Other notes</h2> <h3>Image rendering costs</h3> <p>When using parallax effects, “full-bleed” images that cover the entire page width are also popular. One approach is to simply use a large centered background image for all clients, regardless of screen size; alternately, a responsive <code>@media</code> query-style approach can be taken where separate images are cut to fit within common screen widths like 1024, 1280, 1600, 2048 etc. In some cases, however, the single-size approach can work quite nicely.</p> <p>In the case of the Flickr homepage, the performance cost in using 2048-pixel-wide background images for all screens seemed to be negligible – even in spite of “wasted” pixels for those browsing at 1024×768. The approach we took uses clip-friendly content, typically a centered “hero” element with shading and color that extends to the far edges. Using this approach, the images are quite width-agnostic. The hero-style images also compress quite nicely as JPEGs thanks to their soft gradients and lighting; as one example, we got a 2048×950-pixel image of a flower down to 68 KB with little effort.</p> <p>Bandwidth aside, the 2048-pixel-wide images clip nicely on screens down to 1024 pixels in width and with no obvious flaws. However, Chrome’s dev tools also show that there are costs associated with decoding, compositing, re-sizing and painting images which should be considered.</p> <p>Testing on my work laptop*, “Image resized (non-cached)” is occasionally shown in Chrome’s timeline → frames view after an Image Decode (JPEG) operation – both of which appear to be expensive, contributing to a frame that took 60 msec in one case. It appears that this happens the first time a large parallax image is scrolled into the viewport. It is unclear why there is a resize (and whether it can be avoided), but I suspect it’s due to the retina display on this particular laptop. I’m not using <code>background-size</code> or otherwise applying scaling/sizing in CSS, merely positioning eg., <code>background-position:50% 50%;</code> and <code>background-repeat: no-repeat;</code>. As curiosity sets in, this author will readily admit he has some more research to do on this front. <img src="https://web.archive.org/web/20130906231042im_/http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif?m=1129645325g" alt=";)" class="wp-smiley"/> </p> <p>There are also aspects to RAM and caching that can affect GPU performance. I did not dig deeply into this specifically for Flickr’s new homepage, but it is worth considering the impact of the complexity and number of layers present and active at any given time. If regular scrolling triggers non-cached image resizes each time an asset is scrolled into view, there may be a cache eviction problem stemming from having too many layers active or present at once.</p> <p class="aside" style="font-size:.95em;">* Work laptop: Mid-2012 15″ Retina MBP, 16 GB RAM, 2.6 Ghz Intel i7, NVIDIA GeForce GT 650M/1024 MB, OS X 10.8.3.</p> <h3>Debugging in action</h3> <p>Here are two videos showing performance of flickr.com/new/ with transforms disabled and enabled, respectively.</p> <h3>Transforms off (marginTop-based parallax)</h3> <object type="application/x-shockwave-flash" width="640" height="361" data="https://web.archive.org/web/20130906231042im_/http://www.flickr.com/apps/video/stewart.swf?v=1.161" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"> <param name="flashvars" value="photo_id=8845365987&photo_secret=cfe2155de7&flickr_show_info_box=true"></param><param name="movie" value="http://www.flickr.com/apps/video/stewart.swf?v=1.161"></param><param name="bgcolor" value="#000000"></param><param name="allowFullScreen" value="true"></param><param name="wmode" value="opaque"></param><embed type="application/x-shockwave-flash" src="https://web.archive.org/web/20130906231042oe_/http://www.flickr.com/apps/video/stewart.swf?v=1.161" bgcolor="#000000" allowfullscreen="true" flashvars="photo_id=8845365987&photo_secret=cfe2155de7&flickr_show_info_box=true" wmode="opaque" height="361" width="640"></embed></object> <p>Notice the huge spikes on the timeline with transforms disabled, indicating many frames that are taking up to 80 msec to draw; this is terrible for performance, “blowing the frame budget” of 16 ms, and lowers UI responsiveness significantly. Red paint rectangles indicate that the whole viewport is being repainted on scroll, a major contributor to performance overhead. With compositing borders, you see that every “strip” of the page – each parallax background, in effect – is rendered as a single layer. A quick check of the FPS meter and “continuous repaint” graphs does not look great.</p> <p class="aside"><b>Side note:</b> Continuous repaint is most useful when not scrolling. The feature causes repeated painting of the viewport, and displays an FPS graph with real-time performance numbers. You can go into the style editor while continuous repaint is on and flip things off, e.g., disabling <code>box-shadow</code>, <code>border-radius</code> or hiding expensive elements via <code>display</code> to see if the frame rate improves.</p> <h3>Transforms on (<code>translate3d()</code>-based parallax)</h3> <object type="application/x-shockwave-flash" width="639" height="364" data="https://web.archive.org/web/20130906231042im_/http://www.flickr.com/apps/video/stewart.swf?v=1.161" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"> <param name="flashvars" value="photo_id=8845359795&photo_secret=5fa8467374&flickr_show_info_box=true"></param><param name="movie" value="http://www.flickr.com/apps/video/stewart.swf?v=1.161"></param><param name="bgcolor" value="#000000"></param><param name="allowFullScreen" value="true"></param><param name="wmode" value="opaque"></param><embed type="application/x-shockwave-flash" src="https://web.archive.org/web/20130906231042oe_/http://www.flickr.com/apps/video/stewart.swf?v=1.161" bgcolor="#000000" allowfullscreen="true" flashvars="photo_id=8845359795&photo_secret=5fa8467374&flickr_show_info_box=true" wmode="opaque" height="364" width="639"></embed></object> <p>With GPU acceleration, you see much-improved frame times, thus a higher framerate and a smoother, more-responsive UI. There is still the occasional spike when a new image scrolls into view, but there is much less jank overall than before. Paint rectangles are much less common thanks to the GPU-accelerated compositing, and layer borders now indicate that more individual elements are being promoted. The FPS meter and continuous repaint mode does have a few dips and spikes, but performance is notably improved.</p> <p>You may notice that I intentionally trigger video playback in this case, to see how it performs. The flashing red is the result of repainting as the video plays back – and in spite of <code>overflow: hidden</code>-based clipping we apply for the parallax effect on the video, it’s interesting to notice that the overflowed content, while not visible, is also being painted.</p> <h2>Miscellany</h2> <h3>Random bits: HTML5 <video></h3> <p class="figure"> <img src="https://web.archive.org/web/20130906231042im_/http://farm3.staticflickr.com/2865/8859573578_a1777dc0db_c.jpg" width="800" height="273" alt=""><br/> <span class="caption"><br/> A frame from a .webm and H.264-encoded video, shown in the mobile portion of Flickr’s redesigned home page.<br/> </span> </p> <p>We wanted the signed-out Flickr homepage to highlight our mobile offerings, including an animation or video showing a subtly-rotating iPhone demoing the Flickr iOS app on a static background. Instead of an inline video box, it felt appropriate to have a full-width video following the pattern used for the parallax images. The implementation is nearly the same, and simply uses a <video> element instead of a CSS background.</p> <p>With video, the usual questions came up around performance and file size: Would a 2048-pixel-wide video be too heavy for older computers to play back? What if we cropped the video only to be as wide as needed to cover the area being animated (eg., 500 pixels), and used a static JPEG background to fill in the remainder of the space?</p> <p>As it turned out, encoding a 2048×700 video and positioning it like a background element – even including a slight parallax effect – was quite reasonable. Playback was flawless on modern laptops and desktops, and even a 2006-era 1.2 GHz Fujitsu laptop running WinXP was able to run the video at reasonable speed. Per rendering documentation from the Chrome team, <video> elements are automatically promoted to layers for the GPU where applicable and thus benefit from accelerated rendering. Due to the inline nature of the video, we excluded it from display on mobile devices, and show a static image to clients that don’t support HTML5 video.</p> <p>Perhaps the most interesting aspect of the video was file size. In our case, the WebM-encoded video (supported natively in Chrome, Firefox, and Opera) was clearly able to optimize for the low amount of motion within the wide frame, as eight seconds of 2048×700 video at 24 fps resulted in a <code>.webm</code> file of only <i>900 KB</i>. Impressive! By comparison, the H.264-encoded equivalent ended up being about 3.8 MB, with a matching data rate of ~3.8 mbps.</p> <h3>The “Justified” View</h3> <p>It’s worth mentioning that the Justified photos at the bottom of the page lazy-load in, and have been excluded from any additional display optimizations in this case. There is an initial spike with the render and subsequent loading of images, but things settle down pretty quickly. Blindly assigning translate-type transforms to the Justified photo container – a complex beast in and of itself – causes all sorts of rendering hell to break loose.</p> <h2>In Review</h2> <p>This article represents my findings and approach to getting GPU-accelerated compositing working for background images in the Webkit-based Chrome and Safari browsers, in May 2013. With ever-changing rendering engines getting smarter over time, your mileage may vary as the best route to the “fast path” changes. As numerous other articles have said regarding performance, “don’t <i>guess</i> it, <u>test</u> it.”</p> <p>To recap:</p> <ul> <li><b>Painting</b>: Expensive. Repaints should be minimal, and limited to small areas. Reduce by carefully choosing layers.</li> <li><b>Compositing</b>: Good! Fast when done by the GPU. <li><b>Layers</b>: The secret to speed, when done correctly. Apply sparingly.</li> </ul> <p>References / further reading:</p> <ul> <li><a href="https://web.archive.org/web/20130906231042/https://www.youtube.com/watch?v=8uAYE5G1gSs">Google I/O 2013: Web Page Design with the GPU in Mind</a> (YouTube)</li> <li><a href="https://web.archive.org/web/20130906231042/http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome">GPU Accelerated Compositing in Chrome</a> (Chromium)</li> <li><a href="https://web.archive.org/web/20130906231042/http://www.html5rocks.com/en/tutorials/speed/layers/">Accelerated Compositing in Chrome: The Layer Model</a> (HTML5Rocks)</li> <li><a href="https://web.archive.org/web/20130906231042/http://www.html5rocks.com/en/tutorials/speed/scrolling/">Scrolling</a> (HTML5Rocks)</li> <li><a href="https://web.archive.org/web/20130906231042/http://www.html5rocks.com/en/tutorials/speed/parallax/">Parallaxin’</a> (HTML5Rocks)</li> <li><a href="https://web.archive.org/web/20130906231042/http://jankfree.org/">jankfree.org</a></li> </ul> <p>… And finally, did I mention <a href="https://web.archive.org/web/20130906231042/http://www.flickr.com/new/">we’re hiring</a>? (hint: <code>view-source</code> <img src="https://web.archive.org/web/20130906231042im_/http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif?m=1129645325g" alt=":)" class="wp-smiley"/> )</p> <div id="jp-post-flair" class="sharedaddy sd-like-enabled sd-sharing-enabled"></div> </div><!-- .entry-content --> <footer class="entry-meta"> <span class="cat-links"> <span class="entry-utility-prep entry-utility-prep-cat-links">Posted in</span> <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/performance/" title="View all posts in performance" rel="category tag">performance</a> </span> <span class="sep"> | </span> <span class="tag-links"> <span class="entry-utility-prep entry-utility-prep-tag-links">Tagged</span> <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/tag/chrome/" rel="tag">chrome</a>, <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/tag/compositing/" rel="tag">compositing</a>, <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/tag/dev-tools/" rel="tag">dev tools</a>, <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/tag/gpu/" rel="tag">gpu</a>, <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/tag/hardware-acceleration/" rel="tag">hardware acceleration</a>, <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/tag/painting/" rel="tag">painting</a>, <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/tag/performance/" rel="tag">performance</a> </span> </footer><!-- .entry-meta --> </article><!-- #post-2416 --> </div><!-- #content --> </section><!-- #primary --> <div id="secondary" class="widget-area" role="complementary"> <aside id="search-2" class="widget widget_search"> <form method="get" id="searchform" action="https://web.archive.org/web/20130906231042/http://code.flickr.net/"> <label for="s" class="assistive-text">Search</label> <input type="text" class="field" name="s" id="s" placeholder="Search"/> <input type="submit" class="submit" name="submit" id="searchsubmit" value="Search"/> </form> </aside> <aside id="recent-posts-2" class="widget widget_recent_entries"> <h3 class="widget-title">Recent Posts</h3> <ul> <li> <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2013/09/04/a-summer-at-flickr/" title="A Summer at聽Flickr">A Summer at Flickr</a> </li> <li> <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2013/06/14/pre-generating-justified-views/" title="Pre-generating Justified聽Views">Pre-generating Justified Views</a> </li> <li> <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2013/06/04/adventures-in-jank-busting-parallax-performance-and-the-new-flickr-home-page/" title="Adventures in Jank Busting: Parallax, performance, and the new Flickr Home聽Page">Adventures in Jank Busting: Parallax, performance, and the new Flickr Home Page</a> </li> <li> <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2013/03/26/using-redis-as-a-secondary-index-for-mysql/" title="Using Redis as a Secondary Index for聽MySQL">Using Redis as a Secondary Index for MySQL</a> </li> <li> <a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2012/12/21/redis-global-locks-redux/" title="Redis Global Locks聽Redux">Redis Global Locks Redux</a> </li> </ul> </aside><aside id="archives-2" class="widget widget_archive"><h3 class="widget-title">Archives</h3> <ul> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2013/09/" title="September 2013">September 2013</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2013/06/" title="June 2013">June 2013</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2013/03/" title="March 2013">March 2013</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2012/12/" title="December 2012">December 2012</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2012/10/" title="October 2012">October 2012</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2012/07/" title="July 2012">July 2012</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2012/06/" title="June 2012">June 2012</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2012/05/" title="May 2012">May 2012</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2012/04/" title="April 2012">April 2012</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2012/02/" title="February 2012">February 2012</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2012/01/" title="January 2012">January 2012</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2011/12/" title="December 2011">December 2011</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2011/10/" title="October 2011">October 2011</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2011/09/" title="September 2011">September 2011</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2011/08/" title="August 2011">August 2011</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2011/07/" title="July 2011">July 2011</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2011/06/" title="June 2011">June 2011</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2011/03/" title="March 2011">March 2011</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2011/02/" title="February 2011">February 2011</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2011/01/" title="January 2011">January 2011</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/11/" title="November 2010">November 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/10/" title="October 2010">October 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/09/" title="September 2010">September 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/08/" title="August 2010">August 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/07/" title="July 2010">July 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/05/" title="May 2010">May 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/04/" title="April 2010">April 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/03/" title="March 2010">March 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/02/" title="February 2010">February 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2010/01/" title="January 2010">January 2010</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/12/" title="December 2009">December 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/11/" title="November 2009">November 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/10/" title="October 2009">October 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/09/" title="September 2009">September 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/07/" title="July 2009">July 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/06/" title="June 2009">June 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/05/" title="May 2009">May 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/04/" title="April 2009">April 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/03/" title="March 2009">March 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/02/" title="February 2009">February 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2009/01/" title="January 2009">January 2009</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2008/12/" title="December 2008">December 2008</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2008/11/" title="November 2008">November 2008</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2008/10/" title="October 2008">October 2008</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2008/09/" title="September 2008">September 2008</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2008/08/" title="August 2008">August 2008</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2008/07/" title="July 2008">July 2008</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2008/06/" title="June 2008">June 2008</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2008/05/" title="May 2008">May 2008</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/2008/04/" title="April 2008">April 2008</a></li> </ul> </aside><aside id="categories-2" class="widget widget_categories"><h3 class="widget-title">Categories</h3> <ul> <li class="cat-item cat-item-564792"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/change-log/" title="View all posts filed under changelog">changelog</a> </li> <li class="cat-item cat-item-5784"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/event/" title="View all posts filed under event">event</a> </li> <li class="cat-item cat-item-29160"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/geo/" title="All things geo related">geo</a> </li> <li class="cat-item cat-item-34412"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/kittens/" title="View all posts filed under kittens">kittens</a> </li> <li class="cat-item cat-item-171"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/meta/" title="View all posts filed under meta">meta</a> </li> <li class="cat-item cat-item-1930"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/performance/" title="View all posts filed under performance">performance</a> </li> <li class="cat-item cat-item-1"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/uncategorized/" title="View all posts filed under Uncategorized">Uncategorized</a> </li> <li class="cat-item cat-item-249276"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/uploadr/" title="View all posts filed under uploadr">uploadr</a> </li> <li class="cat-item cat-item-830560"><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/category/xulrunner/" title="View all posts filed under xulrunner">xulrunner</a> </li> </ul> </aside><aside id="meta-2" class="widget widget_meta"><h3 class="widget-title">Meta</h3> <ul> <li><a href="https://web.archive.org/web/20130906231042/http://wordpress.com/signup/?ref=wplogin">Register</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://flickrcode.wordpress.com/wp-login.php">Log in</a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/feed/" title="Syndicate this site using RSS 2.0">Entries <abbr title="Really Simple Syndication">RSS</abbr></a></li> <li><a href="https://web.archive.org/web/20130906231042/http://code.flickr.net/comments/feed/" title="The latest comments to all posts in RSS">Comments <abbr title="Really Simple Syndication">RSS</abbr></a></li> <li>Powered by <a href="https://web.archive.org/web/20130906231042/http://vip.wordpress.com/" rel="generator nofollow" class="powered-by-wpcom">WordPress.com VIP</a></li> </ul> </aside> </div><!-- #secondary .widget-area --> </div><!-- #main --> <footer id="colophon" role="contentinfo"> <div id="site-generator"> Theme: Twenty Eleven <span class="sep"> | </span> Powered by <a href="https://web.archive.org/web/20130906231042/http://vip.wordpress.com/" rel="generator nofollow" class="powered-by-wpcom">WordPress.com VIP</a> </div> </footer><!-- #colophon --> </div><!-- #page --> <script type="text/javascript"> var _qevents = _qevents || [], wpcomQuantcastData = {"qacct":"p-18-mFEk4J448M","labels":",language.en,type.wpcom,vip.flickrcode"}; function wpcomQuantcastPixel( labels, options ) { var i, defaults = wpcomQuantcastData, data = { event: 'ajax' }; labels = labels || ''; options = options || {}; if ( typeof labels != 'string' ) options = labels; for ( i in defaults ) { data[i] = defaults[i]; } for ( i in options ) { data[i] = options[i]; } if ( data.labels ) { data.labels += ',' + labels; } else { data.labels = labels; } _qevents.push( data ); }; (function() {var elem = document.createElement('script');elem.src = (document.location.protocol == "https:" ? "https://web.archive.org/web/20130906231042/https://secure" : "https://web.archive.org/web/20130906231042/http://edge") + ".quantserve.com/quant.js";elem.async = true;elem.type = "text/javascript";var scpt = document.getElementsByTagName('script')[0];scpt.parentNode.insertBefore(elem, scpt); })(); _qevents.push( wpcomQuantcastData ); </script> <noscript><div style="display: none;"><img src="//web.archive.org/web/20130906231042im_/http://pixel.quantserve.com/pixel/p-18-mFEk4J448M.gif?labels=%2Clanguage.en%2Ctype.wpcom%2Cvip.flickrcode" height="1" width="1" alt=""/></div></noscript> <script type="text/javascript" src="//web.archive.org/web/20130906231042js_/http://0.gravatar.com/js/gprofiles.js?ver=201336ae"></script> <script type="text/javascript"> /* <![CDATA[ */ var WPGroHo = {"my_hash":""}; /* ]]> */ </script> <script type="text/javascript" src="https://web.archive.org/web/20130906231042js_/http://s0.wp.com/wp-content/mu-plugins/gravatar-hovercards/wpgroho.js?m=1351637563g"></script> <script>jQuery(document).ready(function($){ Gravatar.profile_cb = function( h, d ) { WPGroHo.syncProfileData( h, d ); }; Gravatar.my_hash = WPGroHo.my_hash; Gravatar.init( 'body', '#wp-admin-bar-my-account' ); });</script> <div style="display:none"> </div> <script type="text/javascript" src="https://web.archive.org/web/20130906231042js_/http://s1.wp.com/_static/??-eJzTLy/QTc7PK0nNK9EvyClNz8wr1i+uzCtJrMjITM/IAeKS1CJMEWP94uSizIISoOIM5/yiVL2sYh19yo1yKiotzvAKBvOBRtrn2hoamxkbG5iYGJpkAQCa50E5"></script> <script type="text/javascript"> (function(){ var corecss = document.createElement('link'); var themecss = document.createElement('link'); var corecssurl = "https://web.archive.org/web/20130906231042/http://s0.wp.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/styles/shCore.css?m=1370811927g&ver=3.0.83c"; if ( corecss.setAttribute ) { corecss.setAttribute( "rel", "stylesheet" ); corecss.setAttribute( "type", "text/css" ); corecss.setAttribute( "href", corecssurl ); } else { corecss.rel = "stylesheet"; corecss.href = corecssurl; } document.getElementsByTagName("head")[0].insertBefore( corecss, document.getElementById("syntaxhighlighteranchor") ); var themecssurl = "https://web.archive.org/web/20130906231042/http://s0.wp.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/styles/shThemeDefault.css?m=1363304414g&ver=3.0.83c"; if ( themecss.setAttribute ) { themecss.setAttribute( "rel", "stylesheet" ); themecss.setAttribute( "type", "text/css" ); themecss.setAttribute( "href", themecssurl ); } else { themecss.rel = "stylesheet"; themecss.href = themecssurl; } //document.getElementById("syntaxhighlighteranchor").appendChild(themecss); document.getElementsByTagName("head")[0].insertBefore( themecss, document.getElementById("syntaxhighlighteranchor") ); })(); SyntaxHighlighter.config.strings.expandSource = '+ expand source'; SyntaxHighlighter.config.strings.help = '?'; SyntaxHighlighter.config.strings.alert = 'SyntaxHighlighter\n\n'; SyntaxHighlighter.config.strings.noBrush = 'Can\'t find brush for: '; SyntaxHighlighter.config.strings.brushNotHtmlScript = 'Brush wasn\'t configured for html-script option: '; SyntaxHighlighter.defaults['pad-line-numbers'] = false; SyntaxHighlighter.defaults['toolbar'] = false; SyntaxHighlighter.all(); </script> <script type="text/javascript" src="https://web.archive.org/web/20130906231042js_/http://s1.wp.com/wp-content/js/devicepx.js?m=1373391538g"></script> <script type="text/javascript"> // <![CDATA[ (function() { try{ if ( window.external &&'msIsSiteMode' in window.external) { if (window.external.msIsSiteMode()) { var jl = document.createElement('script'); jl.type='text/javascript'; jl.async=true; jl.src='/wp-content/plugins/ie-sitemode/custom-jumplist.php'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(jl, s); } } }catch(e){} })(); // ]]> </script><script src="https://web.archive.org/web/20130906231042js_/http://s.stats.wordpress.com/w.js?21" type="text/javascript"></script> <script type="text/javascript"> st_go({'blog':'39034126','v':'wpcom','tz':'0','user_id':'0','subd':'flickrcode'}); function st_vt() {var x=document.createElement("img");x.src="https://web.archive.org/web/20130906231042/http://stats.wordpress.com/g.gif?blog=39034126&v=wpcomvt&tz=0&user_id=0&subd=flickrcode&rand="+Math.random();} ex_go({'crypt':'UE40eW5QN0p8M2Y/RE1BNmNJfGhxNCVxUDExYmtXRThKbHcwXTdETWI1alhvb1oseHImN101ZFpEakVpYjlQYVFLYzBaVHRtPz0wXS9bM1lKdVZKQS1NTGJmdUM0ZHJxVkdbSmJHXy45YXpOSn5mZ3omWzBFWFYzeHl0NUwmeElqfE5bZGgldHpOfnJXP1clUWJ1Nm1ORk4mRTctQS8zLWZxMi1FNVp8U2xFQ3A/WGFSRERINUo0X21rZV1OK2M4UEgtPWdnSGg4fC9vRUJ0UXVMMDBScmhORGJ5cEZpa0tuVDJZRGJXNixQcm5zWVRidEhBTjI5X1pWeUMrcA=='}); addLoadEvent(function(){linktracker_init('39034126',0);}); </script> <noscript><img src="https://web.archive.org/web/20130906231042im_/http://stats.wordpress.com/b.gif?v=noscript" style="height:0px;width:0px;overflow:hidden" alt=""/></noscript> <script> if ( 'object' === typeof wpcom_mobile_user_agent_info ) { wpcom_mobile_user_agent_info.init(); var mobileStatsQueryString = ""; if( false !== wpcom_mobile_user_agent_info.matchedPlatformName ) mobileStatsQueryString += "&x_" + 'mobile_platforms' + '=' + wpcom_mobile_user_agent_info.matchedPlatformName; if( false !== wpcom_mobile_user_agent_info.matchedUserAgentName ) mobileStatsQueryString += "&x_" + 'mobile_devices' + '=' + wpcom_mobile_user_agent_info.matchedUserAgentName; if( wpcom_mobile_user_agent_info.isIPad() ) mobileStatsQueryString += "&x_" + 'ipad_views' + '=' + 'views'; if( "" != mobileStatsQueryString ) { new Image().src = document.location.protocol + '//web.archive.org/web/20130906231042/http://stats.wordpress.com/g.gif?v=wpcom-no-pv' + mobileStatsQueryString + '&baba=' + Math.random(); } } </script> </body> </html><!-- FILE ARCHIVED ON 23:10:42 Sep 06, 2013 AND RETRIEVED FROM THE INTERNET ARCHIVE ON 22:15:30 Mar 01, 2025. JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE. ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C. SECTION 108(a)(3)). --> <!-- playback timings (ms): captures_list: 0.72 exclusion.robots: 0.036 exclusion.robots.policy: 0.022 esindex: 0.013 cdx.remote: 6.164 LoadShardBlock: 401.941 (3) PetaboxLoader3.resolve: 210.382 (3) PetaboxLoader3.datanode: 213.337 (4) load_resource: 154.617 -->