<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="FeedCreator 1.7.2" -->
<rss version="2.0">
    <channel>
        <title>Adam Leach | Lifestream</title>
        <description></description>
        <link>http://adamleach.co.uk</link>
        <lastBuildDate>Sun, 20 May 2012 06:28:47 UT</lastBuildDate>
        <generator>FeedCreator 1.7.2</generator>
        <item>
            <title>@thomasfuchs if you report them as spam they appear to get removed from your timeline</title>
            <link>http://adamleach.co.uk/entry/thomasfuchs-if-you-report-them-as-spam-they-appear-to-get-removed-from-you-14-399.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">@<a href="http://twitter.com/thomasfuchs" target="_blank">thomasfuchs</a> if you report them as spam they appear to get removed from your timeline</div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Wed, 09 May 2012 23:31:40 UT</pubDate>
            <guid>/entry/14/399</guid>
        </item>
        <item>
            <title>Added to a feed: CloudFlare &amp; OpenDNS Work Together to Help the Web</title>
            <link>http://adamleach.co.uk/entry/cloudflare--opendns-work-together-to-help-the-web-11-1201.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1201">
<p></p>
<p></p>
<div class="p_embed p_image_embed">
  <a href="http://getfile4.posterous.com/getfile/files.posterous.com/temp-2012-05-03/qICvCxpbCwGtyBdfybdabJJqFhBxEACBFiDrcfubtvBvuyrgamHjsCCjItgg/cloudflare_opendns_savetheweb.png.scaled1000.png"><img alt="Cloudflare_opendns_savetheweb" height="212" src="http://getfile0.posterous.com/getfile/files.posterous.com/temp-2012-05-03/qICvCxpbCwGtyBdfybdabJJqFhBxEACBFiDrcfubtvBvuyrgamHjsCCjItgg/cloudflare_opendns_savetheweb.png.scaled500.png" width="500" /></a>
</div>
<p>Several years ago, some suspected cyber criminals on the Internet wrote a family of malware dubbed DNSChanger. About a year ago, law enforcement tracked down the suspected cyber criminals behind this malware, arrested them, and took over the servers they were using to redirect customers to rogue sites.</p>
<p>As a result of a court order, the Internet Systems Consortium (ISC) under the direction of the FBI, has continued to run the DNS servers used by the malware for the last year. However, the court order will soon expire and those servers are scheduled to be shut down on July 9, 2012. When that happens, hundreds of thousands of Internet users whose systems are still infected and/or affected could lose access to the web, email, and anything else that depends on DNS. This is the story of how two Internet infrastructure startups &mdash; CloudFlare and <a href="http://www.opendns.com" target="_blank">OpenDNS</a> &mdash; are playing a small part to help solve the problem.</p>
<p><strong>A Bit of DNS Background</strong></p>
<p>Up front, in order to understand this story, you need to understand there are two types of DNS servers: recursive and authoritative. Everyone who uses the Internet needs a recursive DNS server. Your ISP usually provides these types of services or you can use a provider like OpenDNS, Google, DNSAdvantage, other public resolvers, or even run a server yourself to handle your recursive DNS queries.</p>
<p>On the other hand, every domain needs at least one authoritative DNS server. Authoritative servers are where a particular domain's records are hosted and published. Many domain registrars provide authoritative DNS servers, or you can use a service like CloudFlare and we provide authoritative DNS. When an Internet user types a Universal Resource Identifier (URI) aka Universal Resource Locator (URL) into their browser, clicks on a link, or sends an email, their computer queries their recursive DNS provider. If the recursive DNS provider has the answer cached then it responds. If it doesn't have the answer cached, or if the answer it has is stale, then the recursive DNS server queries the authoritative DNS server.</p>
<p>As mentioned above, OpenDNS provides recursive DNS. Their customers are web surfers and they provide a terrific service that helps speed up Internet browsing and protect people on the web from malware. CloudFlare provides authoritative DNS. Our customers are websites and we make those sites faster and protect sites from attacks directed at them. While we're often asked if OpenDNS and CloudFlare are competitive, in reality both services are complementary just using different parts of DNS (recursive and authoritative) to achieve a similar mission: a faster, safer, better Internet.</p>
<p><strong>How Suspected Cyber Criminals Use DNS to Do Bad Things</strong></p>
<p>The DNSChanger malware family was designed to change the recursive DNS server that Internet users&rsquo; computers queries. Instead of directing DNS queries at the recursive server you or your ISP configured, the malware modified computer settings to route queries to recursive DNS servers controlled by the suspected cyber criminals.</p>
<p>The job of DNS is to translate a domain name such as dcwg.org, which humans prefer, into an IP address, like 108.162.205.64, which servers and routers can use. If you are a cyber criminal and you can gain control over someone&rsquo;s recursive DNS then you can direct traffic to certain sites to a fake version of the site. Once DNSChanger had web surfers querying rogue recursive DNS servers, all requests for legitimate websites could be directed to a fake website. For example, even if you typed your bank's domain name into your browser, if the suspected cyber criminals control recursive DNS then they can send you to a malicious site and steal your information.</p>
<p>Over the years DNSChanger operated unchecked, more than a million computers and home routers had their DNS configurations modified. Thankfully, law enforcement was able to track down the suspected cyber criminals behind the malware, arrest them, and seize control of the rogue recursive DNS servers. Unfortunately, hundreds of thousands of computers are still using the formerly rogue recursive DNS servers. On July 9, 2012 the court order directing ISC to operate the servers expires and those servers are scheduled to be shut down. On that date, all systems which still have their DNS settings modified by DNSChanger will effectively be cut off from the Internet.</p>
<p><strong>Getting the Word Out</strong></p>
<p>The DNSChanger Working Group (DCWG), a loosely affiliated organization comprised of some of the world&rsquo;s largest and most competent ISPs, search engines vendors, software vendors, security companies, and others, has been working to get the word out about the problem and reduce the impact of the shutdown of the DNSChanger recursive servers. The DCWG launched a website (dcwg.org) to provide information about the malware, let people test whether they are infected, and provide recommendations on how to fix their systems. CloudFlare first became involved when the folks at dcwg.org reached out to us because their site was under heavy load after attention from major media outlets. CloudFlare helped keep the dcwg.org website online under the load caused by media attention over the last 10 days. We offloaded more than 95% of the traffic to the site, ensuring the site ran fast and stable even when it was being featured on the front page of cnn.com.</p>
<p>Unfortunately, one of the challenges in trying to address situations like DNSChanger is that you only know to go to the dcwg.org website if you already know about it. What you needed was something akin to an emergency broadcast system that would inform people who were infected that they had a problem as they surfed the web. In the process of working with the DCWG, we realized we might be able to help.</p>
<p>Some of our engineers created an app named Visitor DNSChanger Detector App. Any website on CloudFlare can enable the app with a single click from our apps marketplace. The app installs a small bit of Javascript on the page that tests visitors to see if they're infected. If the tests do not detect anything, nothing happens. If the tests indicate that the DNSChanger recursive servers are being used, then a banner is displayed across the top of the page and visitors are directed to instructions on how to clean up the infection (more on that in a second).</p>
<p><span style="font-family: arial, sans-serif;"><a href="http://getfile3.posterous.com/getfile/files.posterous.com/temp-2012-05-03/tmGasawDhCspjxIhnquHGgGbuJjElyufCiyECqBiADFodEdcDEAsgwsCkljz/banner_example.png.scaled1000.png"><img alt="Banner_example" height="105" src="http://getfile0.posterous.com/getfile/files.posterous.com/temp-2012-05-03/tmGasawDhCspjxIhnquHGgGbuJjElyufCiyECqBiADFodEdcDEAsgwsCkljz/banner_example.png.scaled500.png" width="500" /></a> More than 470 million people pass through CloudFlare's network on a monthly basis. Our data suggest that more than half of the people infected with DNSChanger would visit at least one site on CloudFlare per month. The power of the Visitor DNSChanger Detector App is that as CloudFlare publishers enable it then there is an increasing likelihood that people who are infected will get information about their infection before they are no longer able to use the Internet on July 9, 2012.</span></p>
<p>While we've made it extremely easy for publishers on CloudFlare's network to help get the word out, we didn't want to restrict participation to only those sites using our service. We therefore decided to release the code for the checks publicly and as open source so anyone who can install a few lines of Javascript on their web pages will be able to install it on their own sites to inform their potentially infected users. You can access the code from the following <a href="https://github.com/cloudflare/dnschanger_detector" target="_blank">GitHub Repo</a>. We're hopeful that sites both large and small will take the time to install the code in order to help inform their visitors who may be infected.</p>
<p><span style="font-family: arial, sans-serif;"><strong>What Should People Notified of This Infection Do?</strong></span></p>
<p><span style="font-family: arial, sans-serif;">While CloudFlare is able to assist with informing web surfers they have an infection, we aren&rsquo;t particularly well situated to actually fix the problem. After all, it isn&rsquo;t our customers that are directly impacted, but rather the customers of our customers. Many of the folks infected can get help from their ISPs, but for some this might not be an option. CloudFlare reached out to David Ulevitch, the CEO of OpenDNS and he saw this as a great opportunity to further OpenDNS's mission of helping build a better Internet. We added <a href="http://www.opendns.com/dns-changer" target="_blank">OpenDNS as a resource</a> for publishers to display to their customers when the Javascript detects the use of the DNSChanger recursive servers.</span></p>
<p><span style="font-family: arial, sans-serif;"><strong>The Power of the DNS</strong></span></p>
<p><span style="font-family: arial, sans-serif;">This incident illustrates to me the importance and power of the DNS system that underpins the Internet. The suspected cyber criminals were able to modify DNS settings to steal advertising revenue and perform other illegal activities. CloudFlare uses authoritative DNS in order to provision powerful tools to make sites faster and even help create a sort of emergency warning system for the Internet. OpenDNS provides high performance recursive DNS caching services for their customers. Combined, we hope to help the DCWG get the word out so the hundreds of thousands of Internet users still impacted by the DNSChanger malware will be able to take steps to ensure they&rsquo;ll be able to use the Internet on July 10, 2012 and beyond.</span></p>
<p><a href="http://blog.cloudflare.com/cloudflare-opendns-work-together-to-save-the">Permalink</a> | <a href="http://blog.cloudflare.com/cloudflare-opendns-work-together-to-save-the#comment">Leave a comment  »</a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Thu, 03 May 2012 15:00:00 UT</pubDate>
            <guid>/entry/11/1201</guid>
        </item>
        <item>
            <title>Liked the video: Domino's Pizza Safe Sound - Menselijk motorgeluid voor elektrische scooter</title>
            <link>http://adamleach.co.uk/entry/dominos-pizza-safe-sound---menselijk-motorgeluid-voor-elektrische-scooter-12-5.html</link>
            <description><![CDATA[
<div class="youtube">
	<div  class="content-wrapper">
		<div  class="content">
					</div>
	</div>
	<div  class="video">
		If you don't see the video, watch it <a href="http://www.youtube.com/watch?v=n17B_uFF4cA&feature=youtube_gdata">here</a>.	
		<embed src="http://www.youtube.com/v/n17B_uFF4cA" type="application/x-shockwave-flash" wmode="transparent" width="300" height="250"></embed>
	</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Fri, 27 Apr 2012 20:57:15 UT</pubDate>
            <guid>/entry/12/5</guid>
        </item>
        <item>
            <title>Once again @itvfootball mess up broadcast of live football game. ...</title>
            <link>http://adamleach.co.uk/entry/once-again-itvfootball-mess-up-broadcast-of-live-football-game-switch-to--14-398.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">Once again @<a href="http://twitter.com/itvfootball" target="_blank">itvfootball</a> mess up broadcast of live football game. Switch to the ITN News studio during the game and now a SD picture on ITVHD</div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Wed, 25 Apr 2012 20:59:22 UT</pubDate>
            <guid>/entry/14/398</guid>
        </item>
        <item>
            <title>Just noticed you can now Google +1 Adwords ads</title>
            <link>http://adamleach.co.uk/entry/just-noticed-you-can-now-google-1-adwords-ads-14-397.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">Just noticed you can now Google +1 Adwords ads</div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Wed, 25 Apr 2012 19:45:01 UT</pubDate>
            <guid>/entry/14/397</guid>
        </item>
        <item>
            <title>Liked the song: Antidote by Swedish House Mafia</title>
            <link>http://adamleach.co.uk/entry/antidote-by-swedish-house-mafia-2-34.html</link>
            <description><![CDATA[<div class="lastfm">
	<div class="title">Liked the song <a href="http://www.last.fm/music/Swedish+House+Mafia/_/Antidote" target="_blank">Antidote by Swedish House Mafia</a></div>
	<div  class="content-wrapper"><div  class="content"></div></div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Mon, 23 Apr 2012 13:40:45 UT</pubDate>
            <guid>/entry/2/34</guid>
        </item>
        <item>
            <title>My Top 1 #lastfm Artists: deadmau5 (65) #music http://t.co/9PBYJUMP</title>
            <link>http://adamleach.co.uk/entry/my-top-1-lastfm-artists-deadmau5-65-music-httptco9pbyjump-14-396.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">My Top 1 #lastfm Artists: deadmau5 (65) #music <a href="http://t.co/9PBYJUMP" target="_blank">http://t.co/9PBYJUMP</a></div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Sun, 22 Apr 2012 21:29:01 UT</pubDate>
            <guid>/entry/14/396</guid>
        </item>
        <item>
            <title>Added to a feed: Expanding the Cloud – Introducing AWS Marketplace</title>
            <link>http://adamleach.co.uk/entry/expanding-the-cloud-o-introducing-aws-marketplace-11-1202.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1202">
<p>Today Amazon Web Services launched <a href="http://aws.amazon.com/marketplace/ref=mkt_blg_wv">AWS Marketplace</a>, an online store that makes it easy for you to find, buy, and immediately start using software and services that run on the AWS Cloud. You can use AWS Marketplace’s 1-Click deployment to quickly launch pre-configured software on your own Amazon EC2 instances and pay only for what you use, by the hour or month. AWS handles billing and payments, and software charges appear on your AWS bill.</p>
<p><img src="http://www.allthingsdistributed.com/images/marketplace.png" width="151" height="646" style="float: right; margin: 0 0 20px 20px;" alt="image" /></p>
<p>Marketplace has software listings from well-known vendors including 10gen, CA, Canonical, Couchbase, Check Point Software, IBM, Microsoft, SAP, Zend, and others, as well as many widely used open source offerings including Wordpress, Drupal, and MediaWiki.</p>
<p>AWS Marketplace brings the same simple and trusted online shopping experience that customers enjoy on Amazon.com to software built for the AWS platform, streamlining the process of doing research and purchasing software. It features a wide selection of development and business software, including software infrastructure, developer tools, and business applications. Product prices are clearly stated and appear on the same bill as your other AWS services.</p>
<p>AWS Marketplace also simplifies many of the challenges software companies face, such as acquiring customers, developing distribution channels, and billing for their software.</p>
<p><strong>Why shop here?</strong></p>
<p>The way businesses are buying applications is changing. There is a new generation of leaders that have very different expectations about how they can select the products and tools they need to be successful. Last week I met with a CIO for a discussion about how her IT department can use AWS to help make their business units be more agile and move faster. One of the stumbling blocks she mentioned was how to select the best software running on AWS, in a way that was completely in line with the “Cloud Experience”: no software to install, no sales cycle, no procurement delays, and a selection of licensing models to choose from. She jokingly asked for an “Amazon 1-Click” experience for software. I am sure she will be a very happy CIO today.</p>
<p>AWS Marketplace features a wide selection of commercial and free IT and business software. AWS Marketplace enables you to compare options, read reviews, and quickly find the software you want.</p>
<p>We wanted to shrink the time between finding what you want and getting it up and running. Once you find software you like, you can deploy that software to your own EC2 instance with 1-Click -- like the CIO suggested -- or using popular management tools like the AWS Console.</p>
<p>In addition, for most products, software prices are clearly posted on the website so you can purchase software immediately, with the payment instrument you already have on file with Amazon Web Services. Software charges appear on the same monthly bill as your AWS infrastructure charges.</p>
<p><strong>Why sell here?</strong></p>
<p>The Amazon Web Services have helped to create great ecosystem of ISVs that are selling software and services to other customers running in the cloud. It has had a true democratization effect: no longer does the dominant vendor in a market automatically get chosen. I have many IT decision makers ask me who are the young and exciting companies they should be paying attention to. Who are the companies that have a native cloud product, who are the ones that have innovative new licensing models, who are the young and hungry companies that break with the old style of enterprise software vending and are truly customer-centric. At the same time the up-and-coming companies often ask me how we can help them get in front of more customers such that they can compete in an open and honest way. And they also often ask whether we can help them with what Amazon.com does so well for its sellers: handle billing and charging.</p>
<p>AWS Marketplace includes both large, well known companies as well as exciting up and coming companies. If you’re a software provider with an offering that runs on the AWS cloud, you can gain new customers, enable usage-based billing without much additional work, and ensure that customers have a fast and easy deployment experience with their software.</p>
<p>AWS Marketplace helps software and SaaS providers find new customers by exposing their products to some of the hundreds of thousands of AWS customers, ranging from individual software developers to large enterprises.</p>
<p>Additionally, if you are interested in adding hourly billing to your software, AWS Marketplace can help. Simply upload an Amazon Machine Image to AWS and provide the hourly cost. Billing is managed by AWS Marketplace, relieving sellers of the responsibility of metering usage, managing customer accounts, and processing payments, leaving software developers more time to focus on building great software.</p>
<p><strong>Summary</strong></p>
<p>At Amazon we have a long experience with buyers and sellers in a marketplace. We know that something great happens when you solve problems for both the people selling things and those buying things – the market becomes more and more vibrant. We know that for buyers it is important to have very convenient ways of discovering and buying products. For sellers it is important to get their products in front of as many relevant customers as possible and make the sales process as painless as possible.</p>
<p>But more important that anything else for both parties is trust: easy to understand product information, high quality, relevant reviews by other customers, that the seller is reputable and has a history of delivery, and that the buyer will only be charged for his exact usage. For the seller it removes the burden of having to manage customers, measuring their usage and collecting payments for it.</p>
<p>The AWS Marketplace is a great step forward in making easier to buy and deploy software. It also makes it dead simple for ISVs for add hourly billing to their offerings and get their software in from of hundreds of thousands of active AWS customers.</p>
<p>For more information see the announcement at the <a href="http://aws.amazon.com/about-aws/whats-new/2012/04/19/introducing-aws-marketplace/">AWS website</a>, the <a href="http://www.youtube.com/watch?v=_fDmapRd_qU">"Introducing AWS Marketplace" video</a>, the posting on the <a href="http://aws.typepad.com/aws/2012/04/the-aws-marketplace-find-compare-and-launch-cloud-software.html">AWS blog</a> and off course visit the <a href="http://aws.amazon.com/marketplace/ref=mkt_blg_wv">AWS Marketplace</a> for a test drive. Happy shopping!</p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Thu, 19 Apr 2012 06:00:00 UT</pubDate>
            <guid>/entry/11/1202</guid>
        </item>
        <item>
            <title>Added to a feed: Do You Want to Help Build the Next AWS Service?</title>
            <link>http://adamleach.co.uk/entry/do-you-want-to-help-build-the-next-aws-service-11-1203.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1203">
<p>Over the past several years I’ve spent much of my time traveling around the world speaking about distributed systems. From building infinitely scalable data stores, architectures for high performance computing, to the challenges imposed by the CAP theorem, there are wonderful, complex, fascinating problems to be solved in the area of distributed computing. During my travels I’ve met thousands of brilliant engineers who are leveraging the cloud to deliver exciting new products and revolutionize IT as we know it. One thing that’s become obvious to me is that there are innovative, inspiring developers in every corner of the planet from Australia to Iceland and from Israel to Peru.</p>
<p>And that leads me to another distributed problem – finding good engineers to help AWS build the next generation of cloud computing services. We’ve got a big vision and to realize it we need to find qualified engineers to join us on our journey. A quick look at the AWS career web sites reveals that we are hiring hundreds of people around the world.</p>
<p><a href="https://us-amazon.icims.com/jobs/search?ss=1&amp;in_iframe=1&amp;searchKeyword=%22http%3A%2F%2Faws.amazon.com%22">Click here for our current job openings in the U.S.</a></p>
<p><a href="https://uk-amazon.icims.com/jobs/search?ss=1&amp;in_iframe=1&amp;searchKeyword=aws&amp;searchLocation=&amp;searchCategory=">Click here for our current job openings in Europe, Asia, and South Africa</a></p>
<p>Distributed problems call for innovative solutions. So next month we will be taking a distributed approach to finding engineers who want to join AWS. On May 17th and 18th we will be traveling to Houston, Minneapolis, and Nashville to interview candidates who want to join the AWS team. If you live in or near one of those cities and are interested in a meeting with us about careers in AWS check out <a href="http://aws.amazon.com/careers/local-events/">this page</a>. You can also simply email your resume to aws-recruiting@amazon.com</p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Thu, 19 Apr 2012 06:00:00 UT</pubDate>
            <guid>/entry/11/1203</guid>
        </item>
        <item>
            <title>@cloakedninjas if you want a road map use Openstreet Maps http://t.co/iY0qLEnk</title>
            <link>http://adamleach.co.uk/entry/cloakedninjas-if-you-want-a-road-map-use-openstreet-maps-httptcoiy0ql-14-395.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">@<a href="http://twitter.com/cloakedninjas" target="_blank">cloakedninjas</a> if you want a road map use Openstreet Maps <a href="http://t.co/iY0qLEnk" target="_blank">http://t.co/iY0qLEnk</a></div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Tue, 17 Apr 2012 17:24:54 UT</pubDate>
            <guid>/entry/14/395</guid>
        </item>
        <item>
            <title>My Top 3 #lastfm Artists: deadmau5 (85), Zedd (10) &amp;amp; deadmau5 &amp;amp; Kaskade (2) ...</title>
            <link>http://adamleach.co.uk/entry/my-top-3-lastfm-artists-deadmau5-85-zedd-10--deadmau5--kaskade-2-14-394.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">My Top 3 #lastfm Artists: deadmau5 (85), Zedd (10) &amp; deadmau5 &amp; Kaskade (2) #music <a href="http://t.co/9PBYJUMP" target="_blank">http://t.co/9PBYJUMP</a></div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Sun, 15 Apr 2012 12:47:14 UT</pubDate>
            <guid>/entry/14/394</guid>
        </item>
        <item>
            <title>Added to a feed: Expanding the Cloud – Introducing Amazon CloudSearch</title>
            <link>http://adamleach.co.uk/entry/expanding-the-cloud-o-introducing-amazon-cloudsearch-11-1204.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1204">
<p>Today Amazon Web Services is introducing <a href="http://aws.amazon.com/cloudsearch">Amazon CloudSearch</a>, a new web service that brings the power of the Amazon.com’s search technology to every developer. Amazon CloudSearch provides a fully-featured search engine that is easy to manage and scale. It offers full-text search with features like faceting and user-defined rank functions. And like most AWS services, Amazon CloudSearch scales automatically as your data and traffic grow, making it an easy choice for applications small to large. With Amazon CloudSearch, developers just create a Search Domain, upload data, and start querying.</p>
<p><strong>Why Search?</strong></p>
<p>Search is an essential part of many of today's cloud-centric applications. While in our daily lives we are mostly familiar with the search functionality offered by web search, there are in fact many more cases where search is a fundamental component of an application. Search is a much broader technology than just the indexing of large collections of web pages. Many organizations have large collections of documents, structured and unstructured, that can benefit from a specialized search service. With the rise of the App developer culture there is an increasing number of consumer data sources that cannot be simply queried with a web search engine. Using specialized ranking functions these apps can give their customers a highly specialized search experience.</p>
<p>And increasingly, search is applied to data that, though called a "document" for the purposes of search, is really just a record in a database or an object in a NoSQL system. On the query side, we are used to seeing search results as users, but search results are increasingly being used at the core of complex distributed systems where the results are consumed by machines, not people.</p>
<p>With these applications in mind, our customers have told us that a cloud-based managed search service is high on their wish lists. Their main motivation is that existing search technologies, both commercial and open source, have proven to be hard to manage and complex to configure.</p>
<p>Amazon CloudSearch will have democratization effect as it offers features that have been out of reach for many customers. With Amazon CloudSearch, a powerful search engine is now in the hands of every developer, at our familiar low prices, using a pay-as-you-go model. It will allow developers to improve functionality of their products, at lower costs with almost zero administration. It is very simple to get started; customers can create a Search Domain, upload their documents, and can immediately start querying.</p>
<p><strong>How it Works</strong></p>
<p>Developers set up a Search Domain -- a set of resources in AWS that will serve as the home for one collection of data. Developers then access their domain through two HTTP-based endpoints: a document upload endpoint and a query endpoint. As developers send documents to the upload endpoint they are quickly incorporated into the searchable index and become searchable.</p>
<p>Developers can upload data either through the AWS console, from the command-line tools, or by sending their own HTTP POST requests to the upload endpoint.</p>
<p>There are three features that make it easy to configure and customize the search results to meet exactly the needs of the application.</p>
<p><strong>Filtering:</strong> Conceptually, this is using a match in a document field to restrict the match set. For example, if documents have a "color" field, you can filter the matches for the color "red".</p>
<p><strong>Ranking:</strong> Search has at least two major phases: matching and ranking. The query specifies which documents match, generating a match set. After that, scores are computed (or direct sort criterion is applied) for each of the matching documents to rank them best to worst. Amazon CloudSearch provides the ability to have customized ranking functions to fine tune the search results.</p>
<p><strong>Faceting:</strong> Faceting allows you to categorize your search results into refinements on which the user can further search. For example, a user might search for ‘umbrellas’, and facets allow you to group the results by price, such as $0-$10, $10-$20, $20-$40, etc. Amazon CloudSearch also allows for result counts to be included in facets, so that each refinement has a count of the number of documents in that group. The example could then be: $0-$10 (4 items), $10-$20 (123 items), $20-$40 (57 items), etc.</p>
<p>For more information on the different configuration possibilities visit the <a href="http://aws.amazon.com/cloudsearch">Amazon CloudSearch detail page</a>.</p>
<p><strong>Automatic Scaling</strong></p>
<p>Amazon CloudSearch is itself built on AWS, which enables it to handle scale.</p>
<p><img src="http://www.allthingsdistributed.com/images/cloudsearch.png" width="600" alt="image" /></p>
<p>Amazon CloudSearch supports both horizontal and vertical scaling. The main search index is kept in memory to ensure that requests can be served at very high rates. As developers add data, CloudSearch increases either the size of your underlying node or it increases the number of nodes in the cluster. To handle growing request rates, the service autoscales the number of instances handling queries.</p>
<p>Amazon CloudSearch is based on more than a decade of developing high quality search technologies for Amazon.com. It has been developed by A9, the Amazon.com subsidiary that focuses on search technologies. The technology that is used at all the different places where you can search on Amazon.com is also at the core of at Amazon CloudSearch.</p>
<p><strong>Summary</strong></p>
<p>With the launch of Amazon CloudSearch the Amazon Web Services remove yet another pain point for developers. Almost every application these days needs some form of search and as such every developer has to spend significant time implementing it. With Amazon CloudSearch developers can now simply focus on their application and leave the management of search to the cloud.</p>
<p>For more information see the <a href="http://aws.amazon.com/cloudsearch">Amazon CloudSearch detail pages</a>, the <a href="http://docs.amazonwebservices.com/cloudsearch/latest/developerguide/SvcIntro.html?r=1756">Amazon CloudSearch Developer Guide</a> and the <a href="http://aws.typepad.com/aws/2012/04/amazon-cloudsearch-start-searching-in-one-hour.html">posting on the AWS developer blog</a>.</p>
<p>You can sign up for the <a href="https://www2.gotomeeting.com/register/699095922">Introduction To Amazon CloudSearch webinar</a> on May 10.</p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Thu, 12 Apr 2012 07:00:00 UT</pubDate>
            <guid>/entry/11/1204</guid>
        </item>
        <item>
            <title>@giffgaff http://t.co/uIwNsmbk are advertising your service via email to one of my spamtraps. ...</title>
            <link>http://adamleach.co.uk/entry/giffgaff-httptcouiwnsmbk-are-advertising-your-service-via-email-to-on-14-392.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">@<a href="http://twitter.com/giffgaff" target="_blank">giffgaff</a> <a href="http://t.co/uIwNsmbk" target="_blank">http://t.co/uIwNsmbk</a> are advertising your service via email to one of my spamtraps. Not a nice company to do business.</div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Wed, 11 Apr 2012 08:43:04 UT</pubDate>
            <guid>/entry/14/392</guid>
        </item>
        <item>
            <title>@giffgaff please don't use companies like http://t. ...</title>
            <link>http://adamleach.co.uk/entry/giffgaff-please-dont-use-companies-like-httptcorvmaf3c8-for-your-adv-14-393.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">@<a href="http://twitter.com/giffgaff" target="_blank">giffgaff</a> please don't use companies like <a href="http://t.co/rVMAF3c8" target="_blank">http://t.co/rVMAF3c8</a> for your advertising campaigns as they are spammers.</div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Wed, 11 Apr 2012 06:22:10 UT</pubDate>
            <guid>/entry/14/393</guid>
        </item>
        <item>
            <title>Added to a feed: Don’t docwrite scripts</title>
            <link>http://adamleach.co.uk/entry/donyt-docwrite-scripts-11-1205.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1205">
<p>In yesterday’s blog post, <a href="http://www.stevesouders.com/blog/2012/04/09/making-the-http-archive-faster/">Making the HTTP Archive faster</a>, one of the biggest speedups came from <em>not</em> using a script loader. It turns out that script loader was using <code>document.write</code> to load scripts dynamically. I wrote about the <code>document.write</code> technique in <a href="http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/">Loading Script Without Blocking</a> back in April 2009, as well as in <a href="http://www.amazon.com/dp/0596522304">Even Faster Web Sites</a> (chapter 4). It looks something like this:</p>
<pre class="codesample">document.write('&lt;script src="http://www.stevesouders.com/blog' + src + '" type="text/javascript"&gt;&lt;/script&gt;'):</pre>
<p>The problem with <code>document.write</code> for script loading is:</p>
<ul>
  <li>Every DOM element <em>below</em> the inserted script is blocked from rendering until the script is done downloading (<a href="http://stevesouders.com/cuzillion/?c0=bi1hfff0_0_f&amp;c1=bj1wfff4_0_f&amp;c2=bi1hfff0_0_f">example</a>).</li>
  <li>It blocks other dynamic scripts (<a title="document.write script blocks async script" href="http://stevesouders.com/cuzillion/?c0=hj1wfff2_0_f&amp;c1=bj1dfff2_0_f">example</a>). One exception is if multiple scripts are inserted using <code>document.write</code> within the same SCRIPT block (<a title="Two document.write scripts in one SCRIPT block" href="http://stevesouders.com/cuzillion/?c0=hj1wfff2_0_f&amp;c1=hj1wfff2_0_f">example</a>).</li>
</ul>
<p>Because the script loader was using <code>document.write</code>, the page I was optimizing rendered late and other async scripts in the page took longer to download. I removed the script loader and instead wrote my own code to load the script asynchronously following the createElement-insertBefore pattern popularized by the <a href="http://code.google.com/apis/analytics/docs/tracking/asyncUsageGuide.html">Google Analytics async snippet</a>:</p>
<pre class="codesample">var sNew = document.createElement("script");
sNew.async = true;
sNew.src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js";
var s0 = document.getElementsByTagName('script')[0];
s0.parentNode.insertBefore(sNew, s0);</pre>
<p>Why does using <code>document.write</code> to dynamically insert scripts produce these bad performance effects?</p>
<p>It’s really not surprising if we walk through it step-by-step: We know that loading scripts using normal SCRIPT SRC= markup blocks rendering for all subsequent DOM elements. And we know that <code>document.write</code> is evaluated immediately before script execution releases control and the page resumes being parsed. Therefore, the <code>document.write</code> technique inserts a script using normal SCRIPT SRC= which blocks the rest of the page from rendering.</p>
<p>On the other hand, scripts inserted using the createElement-insertBefore technique do <em>not</em> block rendering. In fact, if <code>document.write</code> generated a createElement-insertBefore snippet then rendering would also <em>not</em> be blocked.</p>
<p>At the bottom of my <a href="http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/">Loading Script Without Blocking</a> blog post is a decision tree to help developers choose which async technique to use under different scenarios. If you look closely you’ll notice that <code>document.write</code> is <em>never</em> recommended. A lot of things change on the Web, but that advice was true in 2009 and is still true today.</p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Wed, 11 Apr 2012 00:29:47 UT</pubDate>
            <guid>/entry/11/1205</guid>
        </item>
        <item>
            <title>Added to a feed: Making the HTTP Archive faster</title>
            <link>http://adamleach.co.uk/entry/making-the-http-archive-faster-11-1206.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1206">
<p>This week I <em>finally</em> got time to do some coding on the <a href="http://httparchive.org/">HTTP Archive</a>. Coincidentally (ironically?) I needed to focus on performance. Hah! This turned out to be a good story with a few takeaways – info about the HTTP Archive, some MySQL optimizations, and a lesson learned about dynamic script loaders.</p>
<h3>Setting the stage</h3>
<p>The <a href="http://httparchive.org/">HTTP Archive</a> started in November 2010 by analyzing 10K URLs and storing their information (subresource URLs, HTTP headers, sizes, etc.) in a MySQL database. We do these runs twice each month. In November 2011 we began increasing the number of URLs to 25K, 50K, 75K, and finally hit 100K this month. Our goal is to hit 1M URLs by the end of 2012.</p>
<p><a href="http://httparchive.org/trends.php#numurls"><img class="aligncenter" title="URLs analyzed" src="http://stevesouders.com/images/ha-urls-20120401.png" alt="" width="490" /></a></p>
<p>The MySQL schema in use today is by-and-large the same one I wrote in a few hours back in November 2010. I didn’t spend much time on it – I’ve created numerous databases like this and was able to quickly get something that got the job done and was fast. I knew it wouldn’t scale as the size of the archive and number of URLs grew, but I left that for another day.</p>
<p>That day had arrived.</p>
<h3>DB schema</h3>
<p>The website was feeling slow. I figured I had reached that curve in the hockey stick where my year-old schema that worked on two orders of magnitude less data was showing its warts. I saw plenty of slow queries in the log. I occasionally did some profiling and was easily able to identify queries that took 500 ms or more; some even took 10+ seconds. I’ve built big databases before and had some tricks up my sleeve so I sat down today to pinpoint the long poles in the tent and cut them down.</p>
<p>The first was pretty simple. The <code>urls</code> table has over 1M URLs. The only index was based on the URL string – a blob. It took 500-1000 ms to do a lookup. The main place this happens is looking up the URL’s rank, for example, in the last crawl <a href="http://httparchive.org/viewsite.php?pageid=989830">Whole Foods</a> was ranked 5,872 (according to <a href="http://www.alexa.com/siteinfo/wholefoodsmarket.com">Alexa</a>). This is a fairly non-critical piece of information, so slowing down the page 500-1000 ms wasn’t acceptable. Plus this seems like a simple lookup ripe for optimizing.</p>
<p>When I described this problem to my <a href="http://velocityconf.com/">Velocity</a> co-chair, <a href="http://www.kitchensoap.com/">John Allspaw</a>, he suggested creating a hash for the URL that would be faster to index. I understood the concept but had never done this before. I didn’t find any obvious pointers out there on “the Web” so I rolled my own. I started with <code>md5()</code>, but that produced a fairly long string that was alphanumeric (hex):</p>
<pre class="codesample">select md5("http://www.wholefoodsmarket.com/");
=&gt; 0a0936fe5c690a3b468a6895efaaff83</pre>
<p>I didn’t think it would be that much faster to index off the <code>md5()</code> hex string (although I didn’t test this). Assuming that <code>md5()</code> strings are evenly distributed, I settled on taking a substring:</p>
<pre class="codesample">select substring(md5("http://www.wholefoodsmarket.com/"), 1, 4);
=&gt; 0a09</pre>
<p>This was still hex and I thought an int would be a faster index (but again, I didn’t test this). So I added a call to <code>conv()</code> to convert the hex to an int:</p>
<pre class="codesample">select conv(substring(md5("http://www.wholefoodsmarket.com/"), 1, 4), 16, 10);
=&gt; 2569</pre>
<p>I was pretty happy. This maps URLs across 64K hashes. I’m assuming they’re evenly distributed. This conversion is only done a few times per page so the overhead is low. If you have a better solution please comment below, but overall I thought this would work – and it did! Those 500+ ms queries went down to &lt; 1 ms. Yay!</p>
<p>But the page was still slow. Darn!</p>
<h3>Duh – it’s the frontend</h3>
<p>This and a few other MySQL changes shaved a good 2-3 seconds of the page load time but the page still felt slow. The biggest problem was rendering – I could tell the page arrived quickly but something was blocking the rendering. This is more familiar performance territory for me so I gleefully rolled up my sleeves and pulled out my WPO toolbox.</p>
<p>The page being optimized is <a href="http://httparchive.org/viewsite.php?u=http%3A%2F%2Fwww.wholefoodsmarket.com%2F&amp;l=Mar%2015%202012">viewsite.php</a>. I used <a href="http://webpagetest.org/">WebPagetest</a> to capture a waterfall chart and screenshots for Chrome 18, Firefox 11, IE 8, and IE 9. The blocking behavior and rendering times were not what I consider high performance. (Click on the waterfall chart to go to the detailed WebPagetest results.)</p>
<p>Chrome 18:<br />
<a href="http://www.webpagetest.org/video/compare.php?tests=120406_9K_3W84V-r%3A1-c%3A0&amp;thumbSize=200&amp;ival=100&amp;end=all"><img class="aligncenter" title="Chrome before" src="http://stevesouders.com/images/ha-wf-chrome-before.png" alt="" width="480" /></a></p>
<p>Firefox 11:<br />
<a href="http://www.webpagetest.org/video/compare.php?tests=120406_60_3W857-r%3A1-c%3A0&amp;thumbSize=200&amp;ival=100&amp;end=all"><img class="aligncenter" title="Firefox before" src="http://stevesouders.com/images/ha-wf-ff-before.png" alt="" width="480" /></a></p>
<p>Internet Explorer 8:<br />
<a href="http://www.webpagetest.org/video/compare.php?tests=120406_SQ_3W858-r%3A1-c%3A0&amp;thumbSize=200&amp;ival=100&amp;end=all"><img class="aligncenter" title="Internet Explorer 8 before" src="http://stevesouders.com/images/ha-wf-ie8-before.png" alt="" width="480" /></a></p>
<p>Internet Explorer 9:<br />
<a href="http://www.webpagetest.org/video/compare.php?tests=120406_RJ_3W85D-r%3A1-c%3A0&amp;thumbSize=200&amp;ival=100&amp;end=all"><img class="aligncenter" title="Internet Explorer 9 before" src="http://stevesouders.com/images/ha-wf-ie9-before.png" alt="" width="480" /></a></p>
<p>These waterfall charts looked really wrong to me. The start render times (green vertical line) were all too high: Chrome 1.2 seconds, Firefox 2.6 seconds, IE8 1.6 seconds, and IE9 2.4 seconds. Also, too many resources were downloading and potentially blocking start render. This page has a lot of content, but most of the scripts are loaded asynchronously and so shouldn’t block rendering. Something was defeating that optimization.</p>
<h3>Docwrite blocks</h3>
<p>I immediately honed in on <code>jquery.min.js</code> because it was often in the critical path or appeared to push out the start render time. I saw in the code that it was being loaded using <a title="Google Libraries API" href="https://developers.google.com/speed/libraries/">Google Libraries API</a>. Here’s the code that was being used to load <code>jquery.min.js</code>:</p>
<pre class="codesample">&lt;script src="http://www.google.com/jsapi"&gt;&lt;/script&gt;
&lt;script&gt;
google.load("jquery", "1.5.1");
&lt;/script&gt;</pre>
<p>I’ve looked at (and <a title="ControlJS" href="http://stevesouders.com/controljs/">built</a>) numerous async script loaders and know there are a lot of details to get right, so I dug into the <a href="http://www.google.com/jsapi"><code>jsapi</code></a> script to see what was happening. I saw the typical createElement-insertBefore pattern popularized by the <a href="http://code.google.com/apis/analytics/docs/tracking/asyncUsageGuide.html">Google Analytics async snippet</a>. But upon walking through the code I discovered that <code>jquery.min.js</code> was being loaded by this line:</p>
<pre class="codesample">m.write('&lt;script src="http://www.stevesouders.com/blog'+b+'" type="text/javascript"&gt;&lt;/script&gt;'):</pre>
<p>The <code>jsapi</code> script was using <code>document.write</code> to load <code>jquery.min.js</code>. While it’s true that <code>document.write</code> has some asynchronous benefits, it’s more limited than the createElement-insertBefore pattern. Serendipitously, I was just talking with someone a few weeks ago about deprecating the <code>jsapi</code> script because it introduces an extra HTTP request, and instead recommend that people just load the script directly. So that’s what I did.</p>
<h3>We don’t need no stinkin’ script loader</h3>
<p>In my case I knew that <code>jquery.min.js</code> could be loaded async, so I replaced the <code>google.load</code> code with this:</p>
<pre class="codesample">var sNew = document.createElement("script");
sNew.async = true;
sNew.src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js";
var s0 = document.getElementsByTagName('script')[0];
s0.parentNode.insertBefore(sNew, s0);</pre>
<p>This made the start render times and waterfall charts look much better:</p>
<p>Chrome 18:</p>
<p><a href="http://www.webpagetest.org/video/compare.php?tests=120406_RJ_3W84Z-r%3A1-c%3A0&amp;thumbSize=200&amp;ival=100&amp;end=all"><img class="aligncenter" title="Chrome after" src="http://stevesouders.com/images/ha-wf-chrome-after.png" alt="" width="380" height="196" /></a></p>
<p>Firefox 11:</p>
<p><a href="http://www.webpagetest.org/video/compare.php?tests=120406_43_3W85S-r%3A1-c%3A0&amp;thumbSize=200&amp;ival=100&amp;end=all"><img class="aligncenter" title="Firefox after" src="http://stevesouders.com/images/ha-wf-ff-after.png" alt="" width="480" /></a></p>
<p>Internet Explorer 8:</p>
<p><a href="http://www.webpagetest.org/video/compare.php?tests=120406_0E_3W85M-r%3A1-c%3A0&amp;thumbSize=200&amp;ival=100&amp;end=all"><img class="aligncenter" title="IE8 after" src="http://stevesouders.com/images/ha-wf-ie8-after.png" alt="" width="438" height="113" /></a></p>
<p>Internet Explorer 9:</p>
<p><a href="http://www.webpagetest.org/video/compare.php?tests=120406_SX_3W85N-r%3A1-c%3A0&amp;thumbSize=200&amp;ival=100&amp;end=all"><img class="aligncenter" title="IE9 after" src="http://stevesouders.com/images/ha-wf-ie9-after.png" alt="" width="480" /></a></p>
<p>There was better parallelization of downloads and the start render times improved. Chrome went from 1.2 to 0.9 seconds. Firefox went from 2.6 to 1.3 seconds. IE8 went from 1.6 to 1.1 seconds. IE9 went from 2.4 to 1.0 seconds.</p>
<p>This was a fun day spent making the <a href="http://httparchive.org/">HTTP Archive</a> faster. Even though I consider myself a seasoned veteran when it comes to web performance, I still found a handful of takeaways including some oldies that still ring true:</p>
<ul>
  <li>Even for web pages that have significant backend delays, don’t forget to focus on the frontend. After all, that is the <a href="http://www.stevesouders.com/blog/2012/02/10/the-performance-golden-rule/">Performance Golden Rule</a>.</li>
  <li>Be careful using script loaders. They have to handle diverse script loading scenarios across a large number of browsers. If you know what you want it might be better to just do it yourself.</li>
  <li>Be careful using JavaScript libraries. In this case <code>jquery.min.js</code> is only being used for the drop down About menu. That’s 84K (~30K compressed) of JavaScript for a fairly simple behavior.</li>
</ul>
<p>If you’re curious about why document.write results in worse performance for dynamic script loading, I’ll dig into that in tomorrow’s blog post. Hasta mañana.</p>
<p> </p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 10 Apr 2012 02:43:13 UT</pubDate>
            <guid>/entry/11/1206</guid>
        </item>
        <item>
            <title>My Top 3 #lastfm Artists: deadmau5 (38), Zedd (15) &amp;amp; Knife Party (6) #music http://t. ...</title>
            <link>http://adamleach.co.uk/entry/my-top-3-lastfm-artists-deadmau5-38-zedd-15--knife-party-6-music-14-391.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">My Top 3 #lastfm Artists: deadmau5 (38), Zedd (15) &amp; Knife Party (6) #music <a href="http://t.co/9PBYJUMP" target="_blank">http://t.co/9PBYJUMP</a></div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Sun, 08 Apr 2012 16:55:42 UT</pubDate>
            <guid>/entry/14/391</guid>
        </item>
        <item>
            <title>Added to a feed: x-isms in tech culture redux</title>
            <link>http://adamleach.co.uk/entry/x-isms-in-tech-culture-redux-11-1171.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1171">
<p>What a crazy few weeks. Since my <a href="http://blog.tommorris.org/post/18998214249/oppression-identity-and-sexuality">crazy, fuck you to homophobia coming out post</a> almost a month ago, I&#8217;ve seem to have unintentionally gone into full overdrive with the social issues in technology culture posts: discussing how <a href="http://blog.tommorris.org/post/19778985050/newsflash-sexism-in-geek-communities-demeans-everybody">sexism in technology conferences insults everybody</a> by making women and gay men invisible, and by portraying straight men as stupid, misogynistic idiots who think only with their dicks. Then there was the <a href="http://blog.tommorris.org/post/20456932620/brendan-eich-prop-8-and-homophobia">Brendan Eich post</a>. Which wasn&#8217;t really about Brendan Eich so much as about whether it&#8217;s legitimate to call Eich out and the tired old trope about how the oppressed become the oppressors by, err, talking about homophobia on Twitter. Then to round it off, <a href="http://blog.tommorris.org/post/20527148735/brogrammers-diversity-and-defensiveness">a post on the reaction to Ryan Funduk&#8217;s post about drinking in tech culture</a>.</p>
<p>I wanted to share a little reading list: <a href="http://ithaca.arpinum.org/2012/04/02/on-opinions.html">Derailing for Fun and Profit</a> by Peter Aronoff, which deals with the ever so tiresome response &#8220;oh, but they have a right to their opinion&#8221;. Which is really a big old red herring. Sure, people have the right to an opinion. You have the right in the strict legal sense to believe that Queen Elizabeth II is actually a <a href="https://en.wikipedia.org/wiki/David_Icke#Reptilians_and_shape-shifting">shape-shifting lizard from the Draco constellation</a>. Only I also have the right to consider that absolutely fucking crazy and to think that you are off your rocker.</p>
<p>Chris Heilmann has written a post <a href="http://christianheilmann.com/2012/04/08/arguments-on-twitter-are-causing-more-harm-than-good/">discussing whether Twitter is a good place to have these kinds of arguments</a>, and includes the excellent TEDx video from Jay Smooth on racism.</p>
<p>Chris is obviously right about the potential for grandstanding and sloganeering on platforms like Twitter. <span style="text-decoration: line-through;"><em>But</em>, I think he goes too far.</span> <strong>DISREGARD THAT, I&#8217;m an idiot. Chris wasn&#8217;t saying what I think he was saying. Apologies.</strong></p>
<p>I think that with a few obvious limits,<sup id="fnref:p20711886213-1"><a href="http://blog.tommorris.org/#fn:p20711886213-1" rel="footnote">1</a></sup> honesty is a better policy than hushing things up in order to give outsiders the view that the tech community is free of disagreement. However painful talking about things like sexism and homophobia and the <em>social</em> issues around geek culture can be, it&#8217;s better to have the conversation than keep quiet.</p>
<p>Finally, read Natalie Reed&#8217;s <a href="http://freethoughtblogs.com/nataliereed/2012/03/16/hipster-misogyny/">Hipster Misogyny</a>. Because the reaction to the Boston API Hackathon thing was so clearly hipster misogyny. I didn&#8217;t cover it in my post as that wasn&#8217;t what the post was about. Remember <a href="https://kinlane.posterous.com/learning-from-sqoot-making-hackathons-accessi">what they said</a> in their <a href="https://en.wikipedia.org/wiki/Non-apology_apology">non-apology apology</a>? &#8220;While we thought this was a fun, harmless comment poking fun at the fact that hack-a-thons are typically male-dominated, others were offended.&#8221;</p>
<p>Yeah, <em>LOL GUYZ WHY SO SERIOUS ON THE SEXISM SHIT?</em> That about sums it up.</p>
<div class="footnotes">
  <hr />
  <ol>
    <li id="fn:p20711886213-1">
    <p>&#8220;We must respect the other fellow&#8217;s religion, but only in the sense and to the extent that we respect his theory that his wife is beautiful and his children smart.&#8221; —H. L. Mencken. <a href="http://blog.tommorris.org/#fnref:p20711886213-1" rev="footnote">↩</a></p>
    </li>
  </ol>
</div>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Sun, 08 Apr 2012 13:43:19 UT</pubDate>
            <guid>/entry/11/1171</guid>
        </item>
        <item>
            <title>Added to a feed: Reserved Cache Nodes for Amazon ElastiCache</title>
            <link>http://adamleach.co.uk/entry/reserved-cache-nodes-for-amazon-elasticache-11-1172.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1172">
<p><a href="http://aws.amazon.com/elasticache/" target="_self">Amazon ElastiCache</a> makes it easy for you to deploy, scale, and run a cloud-based in-memory cache that is protocol-compliant with Memcached. ElastiCache improves the performance of web applications and reduces the load on your databases by retrieving data from a fast, managed, Memcached-compatible, in-memory caching system, instead of relying entirely on disk-based storage. It can significantly improve throughput for read-heavy or compute-intensive workloads including Social Networking, Mobile and Social Gaming, E-Commerce Sites, Media Sites, and Recommendation Engines.</p>
<p>In order to make ElastiCache an even better value, we are adding a full suite of Reserved Cache Node options -- Light, Medium, and Heavy with both 1 and 3 year terms. See the <a href="http://aws.amazon.com/elasticache/#pricing" target="_self">ElastiCache pricing</a> for additional information. Reserved Cache Nodes can provide savings of up to 70% compared to On-Demand pricing. More information, including pricing, is available on our new <a href="http://aws.amazon.com/elasticache/reserved-cache-nodes" target="_self">Reserved Cache Nodes</a>page.</p>
<p>You can easily migrate from Memcached to ElastiCache using our H<a href="http://aws.amazon.com/elasticache/faqs/#How_do_I_migrate" target="_self">ow Do I Migrate FAQ</a> as a guide; you can also use the <a href="https://s3.amazonaws.com/cloudformation-templates-us-east-1/ElastiCache.template" target="_self">ElastiCache CloudFormation template</a> to launch a cache cluster.</p>
<p>Finally, you&#39;ll also find useful information in the recorded version of our &quot;Turbo-charge Your Apps Using Amazon ElastiCache&quot; webinar:</p>
<div style="text-align: center;">
</div>
<p>-- <a href="https://twitter.com/#!/jeffbarr">Jeff</a>;</p>
<div class="feedflare">
  <a href="http://feeds.feedburner.com/~ff/AmazonWebServicesBlog?a=a1LjquIIneQ:vKYAcrh_mfU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AmazonWebServicesBlog?d=yIl2AUoC8zA" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/AmazonWebServicesBlog?a=a1LjquIIneQ:vKYAcrh_mfU:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/AmazonWebServicesBlog?d=dnMXMwOfBR0" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/AmazonWebServicesBlog?a=a1LjquIIneQ:vKYAcrh_mfU:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AmazonWebServicesBlog?d=7Q72WNTAKBA" alt="image" style="border: 0px;" /></a>
</div>
<img src="http://feeds.feedburner.com/~r/AmazonWebServicesBlog/~4/a1LjquIIneQ" height="1" width="1" alt="image" /></div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Fri, 06 Apr 2012 04:47:55 UT</pubDate>
            <guid>/entry/11/1172</guid>
        </item>
        <item>
            <title>Added to a feed: Customer Conversations - How Intuit and Edmodo Innovate using Amazon RDS</title>
            <link>http://adamleach.co.uk/entry/customer-conversations---how-intuit-and-edmodo-innovate-using-amazon-rds-11-1173.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1173">
<p><b>From tax preparation to safe social networks, Amazon RDS brings new and innovative applications to the cloud</b></p>
<p>Empowering innovation is at the heart of everything we do at Amazon Web Services (AWS). I often get to meet, discuss, and learn from innovators how they are using AWS to deliver transformative applications to their users, customers and partners. Often we think about innovation as doing 'new things' or based on revolutionary new technologies such as DynamoDB, but it is more important to ensure that one can also innovate based on existing paradigms. One of the services that is very successful in driving innovation at our customers in this context is <a href="http://aws.amazon.com/rds">Amazon RDS</a>, the Relational Database Service. Amazon RDS removes the headaches of running a relational database service reliably at scale, allowing Amazon RDS customers to focus on innovation for their customers.</p>
<p>Recently I had great conversations with Troy Otillio, Senior Development Manager at <a href="http://community.intuit.com/">Intuit</a> and Jack Murgia, Senior DevOps Engineer at <a href="http://www.edmodo.com">Edmodo</a>. Troy and his team have added a contextual social offering to the popular TurboTax and Intuit applications. Jack and his engineers have created a safe social app for teachers and students. These innovators use Amazon RDS in conjunction with other Amazon Web Services to build, scale and operate their applications. Below is my dialog with them. Read on.</p>
<p><i>Note: If you want to see how Amazon RDS can enable your creative agenda, sign up for the 60 day <a href="http://aws.amazon.com/rds/free-trial">free trial</a>.</i></p>
<p><i><b>Troy, Jack, Tell me a little bit about your app. What's unique and innovative about your service?</b></i></p>
<p><b>Troy:</b> <a href="http://community.intuit.com/">Live Community</a> Platform is Intuit's flagship Contextual Social offering &#8211; Live Community makes it easy to find answers when and where you need them. This is a unique and innovative platform.</p>
<ul>
  <li>Intelligent Social network - Facilitate topical Q&amp;A conversations among employees, customers and our most valued super contributors.</li>
  <li>Large Seasonal Peaks &#8211; Our largest community supports TurboTax where the peak traffic during February or April is often 100's of times greater than a quiet day in June. Live Community Experience is deeply integrated into the tax experience, so we built a highly responsive and reliable web experience.</li>
  <li>Read-your-mind contextual integration &#8211; Our core innovation and underlying secret sauce involves selecting the most relevant content for a given page if not given user &#8211; to provide the right answer at the right time to our users.</li>
</ul>
<p><b>Jack</b>: <a href="http://www.edmodo.com">Edmodo</a> is the safe social network for education used by a network of over 6 million teachers and students worldwide that allows teachers to create and maintain their classroom communities. Some unique and innovative characteristics of Edmodo are:</p>
<ul>
  <li>Edmodo is as easy to use as other social network sites, but secure - the teacher has the same control over access, content and behavior in Edmodo as he/she does in the classroom.</li>
  <li>Students gain experience they need for the modern workplace, learning how to work responsibly and effectively in a collaborative, project-based manner on a social website.</li>
  <li>Teachers can use Edmodo to share educational content, manage projects and assignments, handle notifications, and conduct quizzes and events.</li>
  <li>Teachers can interact with their colleagues in professional learning networks.</li>
  <li>Schools and districts can claim unique Edmodo web addresses for added communication and customization.</li>
</ul>
<p><b><i>How are your users adopting and responding to your service?</i></b></p>
<p><b>Troy:</b> We moved our service from internal servers to AWS. Our 25+ million strong TurboTax and Intuit user community grows every year and Live Community is an integral component of the overall product experience. Moving to AWS has enabled us with operational agility to deliver more value to those customers without having to worry about scale and infrastructure maintenance. We now have more time to focus on innovation while being confident that when demand increases we can easily add more capacity.</p>
<p><b>Jack:</b>Since our launch in late 2008, we've grown to over 6 million teachers and students globally primarily through word of mouth of teachers who have shared Edmodo with each other. In addition to using Edmodo to engage students in classroom activities, teachers all over the world build profile pages on Edmodo, which they use to discover and share content, meet and stay in contact with other educators, and best practices and top resources.</p>
<p><b><i>Jack, how did this idea come about? How did you choose a SQL approach to solve this problem?</i></b></p>
<p><b>Jack:</b> After years of seeing teachers struggle to share the web with their classroom, Edmodo founders Nic Borg and Jeff O'Hara knew there was a need for a highly scalable, secure social network targeted at K-12. SQL was the right choice because it was an established and proven technology for use in similar environments, and the massive knowledge base that exists around it.</p>
<p><b><i>And how about you Troy? Why did you choose a SQL approach to build your social community app?</i></b></p>
<p><b>Troy:</b> The initial architecture was based on MySQL&#8211; we've continued with use of SQL but are now leveraging RDS. Of course, with as much textual data as we have we are leveraging Lucene/SOLR (a NoSQL solution) for Search and Semantic processing. More recently we've expanded our platform to include additional forms of user interaction observation in support of our real-time analytics &#8211; here we've begun to leverage NoSQL technologies like Redis. Going forward we'll continue to employ a hybrid approach using RDS for the necessary transactional computation and services like <a href="http://aws.amazon.com/dynamodb">DynamoDB</a> for high performance and scalability for structured data.</p>
<p><b><i>What did you find unique about RDS? What has been your experience so far?</i></b></p>
<p><b>Troy:</b> We love RDS &#8211; it's reduced our operational workload by a noticeable factor but even more exciting is the benefits around fast recovery enabled by the Multi-Availability Zone capability. My team often brags about the one-click creation of read replicas, ability to upsize or downsize the database without downtime and automatic back-up. However, the shining moment occurred just last month &#8211; during peak load there was a hardware failure on the Server powering a RDS Master Database &#8211; RDS automatically failed over to the alternate zone within minutes and our customers experience was fully functional shortly thereafter. The best part was that the entire process was what I call Òhands freeÓ and took near zero development effort. With self-hosted databases we would have invested considerable engineering effort to implement, test and retest failover &#8211; to achieve fast recovery with RDS we simply changed our configuration. And when the actual production event took place the recovery required no manual intervention &#8211; the response from our CTO after hearing what happened: &quot;that's cool&quot;.</p>
<p>We encountered a few situations that required help from the Amazon team &#8211; for example, we didn't know that the I/O capacity of the Server is governed by the size of storage and size of the server. When we first attempted to load our production database it took 28 hours &#8211; after a few days of attempts to reduce the load time through well-known optimizations (<a href="http://aws.amazon.com/rds/faqs/#128">mostly documented on the RDS website</a>) we were stuck at 8 hours. We consulted directly with Amazon and learned that the storage and the DB Server size affected I/O throughput &#8211; after altering our size we dropped our load time to 1 hour which was within expectations relative to native database.</p>
<p><b>Jack:</b> Based on our experience during this period of phenomenal growth while our team productivity is stretched to the max, we see that:</p>
<ul>
  <li>RDS is a huge time-saver</li>
  <li>RDS provides peace of mind about our data</li>
</ul>
<p>Anything that saves time and simplifies processes for employees of a young startup has a positive affect that CAN NOT be overstated. The peace of mind part needs no explanation. Nobody on our team regrets moving to RDS MySQL - quite the opposite; we all agree we don't want to think about where we would have been without RDS. We have been able to meet our goal of architecting our application for 0% &quot;maintenance downtime&quot;</p>
<p>Out of the box, RDS' CloudWatch data and graphs speed up the troubleshooting process.</p>
<ul>
  <li>Complete certainty in a DB environment is VERY unique- we never worry that:</li>
  <li>our DB parameters are identical across replicas, and changes propagate at a time of my choosing</li>
  <li>the recoverability of data</li>
</ul>
Lack of root access to the underlying server OS was unique &#8211; but we have found it does not hinder us in anyway. Anything we have needed to accomplish, including a late night upgrade to MySQL 5.5 and implementation of Facebook's Online Schema Change for MySQL has been easily accomplished. 
<p><b><i>This is great to hear. We are glad we RDS meets your needs. Now, what's next on your innovation agenda?</i></b></p>
<p><b>Jack:</b> We want to deliver an even more performance and rock solid experience for our global user base of teachers, students, administrators and parents. We will be:</p>
<ul style="list-style-type: decimal;">
  <li>Building &quot;incident managers&quot; which utilize the cloud watch data and AWS APIs to automatically replace servers and/or re-deploy when problems arise.</li>
  <li>Building &quot;incident creators&quot; - servers which test our ability to maintain peak performance.&nbsp;</li>
</ul>
<p>We believe that by leveraging the services that Amazon provides to the fullest we can continue to scale our exceptional user experience so that Edmodo can be the platform for classrooms around the world on devices of all shapes and sizes.</p>
<p><b>Troy:</b> At Intuit, we can go further to leverage the benefits of elasticity and further improve our resiliency. We are investing in use of CloudFormation coupled with Chef &#8211; the result will enable us to lower costs and further reduce risk.</p>
<p>Prior to AWS we had several tiers that we now think can be delegated to AWS services &#8211; this should free up our team to focus on our domain problems. For example, we are intending to replace our EC2/Memcache tier with ElastiCache, our batch processing with Simple Workflow and Web servers with CloudFront.</p>
<p>With our newfound agility we can launch new services quickly and there are a few on our plate in the near term. In some cases we are refactoring our system into smaller, discrete services, while in other cases we are creating wholesale new services Our core problem domain consists of extracting greater value out of textual and behavioral data which means that use of EMR and even the newly released Workflow should enable us to focus more on the domain and less on the system engineering.</p>
<p><b><i>Troy, Jack, Thank you both very much for sharing your unique experience. I look forward to hearing your progress.</i></b></p>
<p><b>Jack:</b> Thank you. This has been a great dialog.</p>
<p><b>Troy:</b> Thank you Werner. We appreciate the opportunity.</p>
<p>As I noted before, it's a great pleasure to talk to these innovators and how AWS helps their journey. If you have never used RDS before, you can sign up for a <a href="http://aws.amazon.com/rds/free-trial">60 day free trial</a> What innovation will you bring to market? How will it change the world? We won't know until you try and build something.</p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Thu, 05 Apr 2012 15:40:02 UT</pubDate>
            <guid>/entry/11/1173</guid>
        </item>
        <item>
            <title>Added to a feed: Welcome DreamHost!</title>
            <link>http://adamleach.co.uk/entry/welcome-dreamhost-11-1174.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1174">
<p></p>
<p></p>
<div class="p_embed p_image_embed">
  <img alt="Dreamhost_logo" height="500" src="http://getfile6.posterous.com/getfile/files.posterous.com/temp-2012-04-04/DjzDJxhgeljjtxnhjApGjDkdGquJGivustmsznuCifIDHaEwpCBuxpljICeE/dreamhost_logo.png.scaled500.png" width="500" />
</div>
<p><span style="font-size: 15px; font-family: Arial; font-weight: normal; vertical-align: baseline;">We hung out with the <a href="http://dreamhost.com" target="_blank">DreamHost</a> team for the first time at HostingCon in August 2011. They threw a great party, had awesome t-shirts, and exuded the kind of excitement and passion for hosting that CloudFlare has for making websites faster and more secure. We immediately knew we wanted to partner with them.</span><br />
<span style="font-size: 15px; font-family: Arial; font-weight: normal; vertical-align: baseline;"> </span><br />
<span style="font-size: 15px; font-family: Arial; font-weight: normal; vertical-align: baseline;">Fast forward nine months to today and we are happy to announce that DreamHost is now an official Certified Hosting Provider. Beginning today they're offering CloudFlare to all their customers with a one-click-simple integration. Prior to this partnership, we had thousands of DreamHost customers who signed up for CloudFlare directly through our site. Now, every DreamHost customer has simple, easy access to CloudFlare with a click of a button and without having to mess with their DNS. Other bells and whistles like mod_cloudflare are now included in all the default DreamHost configurations, so even existing CloudFlare users on the DreamHost network will benefit.</span></p>
<p><strong><span style="font-size: 15px; font-family: Arial; vertical-align: baseline;">CloudFlare Plus</span></strong></p>
<p><span style="font-size: 15px; font-family: Arial; font-weight: normal; vertical-align: baseline;"><span style="font-size: 15px; font-family: Arial; font-weight: normal; vertical-align: baseline;">DreamHost is the latest <a href="http://www.cloudflare.com/hosting-partners" target="_blank">CloudFlare Certified Hosting Partner</a>, a program that makes CloudFlare one-click simple for any hosts to provide to their customers. We're trying a new experiment and allowing</span>DreamHost to offer a special plan they've dubbed CloudFlare Plus. We worked with them to create this custom CloudFlare plan with the features they thought would be the most interesting for their customers and a price point lower than our current Pro product. For those folks for whom CloudFlare Pro is a bit more than they need, DreamHost now offers another option with some of our most popular paid features.</span></p>
<p><strong><span style="font-family: Arial;"><span style="font-size: 15px;">Just Sayin': CloudFlare &asymp; Voltron</span></span></strong></p>
<p><span style="font-size: 15px; font-family: Arial; font-weight: normal; vertical-align: baseline;">I do have to say that DreamHost will also always hold a special place in my heart for what must be the most fun press release I've ever seen, a full copy of which is below. If you only read one part, read the quote near the end that I bolded which is certifiably awesome.</span></p>
<p><span style="font-size: 15px; font-family: Arial; font-weight: normal; vertical-align: baseline;"><br />
</span></p>
<blockquote>
  <p><span style="font-family: Arial;"><span style="font-size: 15px;">FOR IMMEDIATE RELEASE</span></span></p>
  <p style="text-align: center;"><strong><span style="font-family: Arial;"><span style="font-size: 15px;">DreamHost Partners With CloudFlare</span></span></strong></p>
  <p style="text-align: center;"><em><span style="font-family: Arial;"><span style="font-size: 15px;">CloudFlare to Provide Free Site Performance Optimization and Security Services for all DreamHost customers</span></span></em></p>
  <p style="text-align: left;"><span style="font-family: Arial;"><span style="font-size: 15px;">LOS ANGELES, California&mdash;April 5th, 2012&mdash;DreamHost, a global full-service web hosting company, has today announced a partnership with leading Internet web performance and security company, CloudFlare. DreamHost customers now have immediate access to CloudFlare's robust infrastructure at little or no cost as a standard feature of their hosting plans.</span></span></p>
  <p><span style="font-family: Arial;"><span style="font-size: 15px;">Shared web hosting customers, for many years, have rarely been able to take advantage of the benefits provided by Content Delivery Networks as a result of either the cost or complexity involved. CloudFlare has removed both barriers to entry by distilling the entire setup and configuration process down to a single checkbox and removing the cost entirely. CloudFlare brings the performance and security tools previously available only to Internet giants to anyone with a website.</span></span></p>
  <p><span style="font-family: Arial;"><span style="font-size: 15px;">Hundreds of nodes around the globe power CloudFlare's network ensuring that websites load quickly and consistently, regardless of where in the world users happen to be. CloudFlare's Anycast technology works with static and dynamic sites, routing users to the node on their network for the fastest performance &mdash; all without breaking a sweat!</span></span></p>
  <p><span style="font-family: Arial;"><span style="font-size: 15px;">CloudFlare's &ldquo;Always Online&rdquo; technology ensures that sites taking advantage of the CloudFlare platform will remain online, continuing to serve cached content, even if the hosting servers on which they are housed become temporarily unreachable. If the hosting industry had a holy grail, it might look a little something like CloudFlare.</span></span></p>
  <p><span style="font-family: Arial;"><span style="font-size: 15px;">In addition to CloudFlare's free offering, DreamHost has also worked with the CloudFlare team to create &ldquo;CloudFlare Plus,&rdquo; a bundling of CloudFlare's most popular features available exclusively to DreamHost customers. CloudFlare Plus is an optional paid upgrade, weighing in at $9.95 per month, and adds automatic image optimization and support for Secure Socket Layer (SSL) connections. Provisioning of either option has been integrated within the DreamHost customer control panel.</span></span></p>
  <p><strong><span style="font-family: Arial;"><span style="font-size: 15px;">&ldquo;When we first met with the CloudFlare team at HostingCon 2011 we had no idea if what they were telling us was true,&rdquo; said Kathy Brahm, DreamHost's Vice President of Customer Experience and Partnerships. &ldquo;You know how typical sales people can be &mdash; schmoozy, smiley, 'Let-me-buy-you-dinnery', handsy &hellip; all the while making outrageous claims about their product. CloudFlare's team has been the complete opposite of those &mdash; and a true pleasure to deal with. We've spent the past few weeks putting CloudFlare through its paces and running some tests of our own. Some of us nearly fainted when the first speed tests came back. One guy cried. Me? I buried my feelings deep inside so I don't have to deal with them. It's just what I do.&rdquo;</span></span></strong></p>
  <p><span style="font-family: Arial;"><span style="font-size: 15px;">&ldquo;From days of long ago, from uncharted regions of the web, comes a legend; the legend of CloudFlare, Defender of the Interwebs: a mighty robot, loved by good, feared by evil,&rdquo; explains Matthew Prince, co-founder and CEO of CloudFlare, doing his best Peter Cullen impersonation. &ldquo;As CloudFlare's legend grew, peace settled across the network. From Los Angeles, an Interweb Alliance was led by DreamHost. Together with other good hosts of the network, DreamHost helped maintain peace throughout the Interwebs, until a new horrible menace threatened. A closer relationship with CloudFlare was needed. This is the story of the super force of web explorers, specially trained by DreamHost, to more tightly integrate CloudFlare, Defender of the Interwebs!&rdquo;</span></span></p>
  <p><span style="font-family: Arial;"><span style="font-size: 15px;">CloudFlare's free offering and the DreamHost-exclusive &ldquo;CloudFlare Plus&rdquo; are now available to all DreamHost customers.</span></span></p>
</blockquote>
<p> </p>
<p><a href="http://blog.cloudflare.com/welcome-dreamhost">Permalink</a> | <a href="http://blog.cloudflare.com/welcome-dreamhost#comment">Leave a comment  »</a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Thu, 05 Apr 2012 15:01:38 UT</pubDate>
            <guid>/entry/11/1174</guid>
        </item>
        <item>
            <title>Added to a feed: Infinite Monkey Twitter</title>
            <link>http://adamleach.co.uk/entry/infinite-monkey-twitter-11-1175.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1175">The Infinite Monkey Theorem states: a monkey hitting keys at random on a typewriter keyboard for an infinite amount of time will almost surely type a given text, such as the complete works of William Shakespeare. This made me think&#8230; &#8230;
<p class="read-more"><a href="http://blog.lotas-smartman.net/infinite-monkey-twitter">Read more &#187;</a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/MGlv2VsIFopuIJKGN4IsYpME8Qc/0/da"><img src="http://feedads.g.doubleclick.net/~a/MGlv2VsIFopuIJKGN4IsYpME8Qc/0/di" ismap="ismap" alt="image" style="border: 0px;" /></a><br />
<a href="http://feedads.g.doubleclick.net/~a/MGlv2VsIFopuIJKGN4IsYpME8Qc/1/da"><img src="http://feedads.g.doubleclick.net/~a/MGlv2VsIFopuIJKGN4IsYpME8Qc/1/di" ismap="ismap" alt="image" style="border: 0px;" /></a></p>
<div class="feedflare">
  <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/lotas?d=yIl2AUoC8zA" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/lotas?d=dnMXMwOfBR0" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/lotas?d=7Q72WNTAKBA" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lotas?i=led6pfh4rKE:qenN_C9uRmI:D7DqB2pKExk" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:JEwB19i1-c4"><img src="http://feeds.feedburner.com/~ff/lotas?i=led6pfh4rKE:qenN_C9uRmI:JEwB19i1-c4" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:ozPqQDaSF7U"><img src="http://feeds.feedburner.com/~ff/lotas?i=led6pfh4rKE:qenN_C9uRmI:ozPqQDaSF7U" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:XQ266DUsA9M"><img src="http://feeds.feedburner.com/~ff/lotas?d=XQ266DUsA9M" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:ANkz6nJbUoM"><img src="http://feeds.feedburner.com/~ff/lotas?d=ANkz6nJbUoM" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/lotas?d=qj6IDK7rITs" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/lotas?i=led6pfh4rKE:qenN_C9uRmI:V_sGLiPBpWU" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/lotas?d=YwkR-u9nhCs" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=led6pfh4rKE:qenN_C9uRmI:wd9GD17jvC4"><img src="http://feeds.feedburner.com/~ff/lotas?d=wd9GD17jvC4" alt="image" style="border: 0px;" /></a>
</div>
<img src="http://feeds.feedburner.com/~r/lotas/~4/led6pfh4rKE" height="1" width="1" alt="image" /></div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Wed, 04 Apr 2012 14:35:43 UT</pubDate>
            <guid>/entry/11/1175</guid>
        </item>
        <item>
            <title>Added to a feed: Getting started with Natural Load Testing</title>
            <link>http://adamleach.co.uk/entry/getting-started-with-natural-load-testing-11-1176.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1176">
<p>I've been following the products of <a href="https://wondernetwork.com/">WonderNetwork</a> for a while as they do some interesting stuff with servers around the world. I particularly like <a href="https://wonderproxy.com/signup/vpn">Wonder VPN</a> as a drop dead simple and reliable VPN is very handy for any mobile user who wants some security when using a wireless network in Starbucks!</p>
<p>Recently they have been working on a new product called <a href="https://load.wondernetwork.com">Natural Load Testing</a> which is intended to make load testing your web application very simple. It's a very friendly service which is immediately apparent on the home page where it says "not logged in, no greeting. how sad". It's a little touch that appeals to me.</p>
<p>Natural Load Testing is currently in private beta and the WonderNetwork guys invited me into the beta and have been generous enough to spend a small part of their marketing budget to enable me to be able to publish this article. They've even managed to cope with my list of complaints and still talk to me! In this tutorial I will walk through how to use the Natural Load Testing product (as is today) to get some results. Interpreting the results and improving your website and server infrastructure is your job though :)</p>
<h3>Getting Started</h3>
<p>Natural Load Testing (shortened to NLT in this article!) consists of 4 main areas where you interact with it:</p>
<ul>
  <li>Creating tests</li>
  <li>Configuring test suites</li>
  <li>Running test suites</li>
  <li>Reviewing results</li>
</ul>
<p>Upon log in, the home page consists of a set of friendly buttons:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT1.png" alt="Natural Load Testing home page" width="600" height="341" style="border: 0px;" /></p>
<p>We start at the beginning: creating tests.</p>
<h3>Creating tests</h3>
<p>When load testing you need to configure your testing tool with the URLs of the pages and resources the you want to be tested. Natural Load Testing makes this job trivial by cleverly leveraging their proxy technology. By configuring your browser to use the NLT proxy, it will record every page you visit and provide you with a list of URLs which you can then use to create tests.</p>
<p>Obviously, as load testing involves hitting the server with a lot of requests, by the time NLT is out of beta, you will need to authorise each domain that you want to use. This is done in the "Manage Authorised Domains" section.</p>
<p>There is a helpful page on the NLT site that explains how to do this. Don't forget to turn off the proxy after recording. The WonderNetwork people have also remembered that you may want to record HTTPS traffic for load testing, and have provided a root certificate that you'll need to install. Again, there's help available on how to install this.</p>
<p>Once you have recorded some URLs, you can then click on the "Create" button and you are presented with a list of the most recent URLs you have recorded.</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT2.png" alt="Recorded URLS" width="600" height="532" style="border: 0px;" /></p>
<p>To create the test, you select the URLs that you require to be included (the checkbox in the header selects all within the group, which is very handy!). You then choose a name that will help you remember what this test does and create the test.</p>
<p>In order to create some interesting load tests on our site, I created a good few tests which I could then group into test suites.</p>
<h3>Configuring test suites</h3>
<p>Your tests are grouped into suites that are then run either sequentially or as a set of random loads. To create a suite, you click on the "Configure" button which then shows you the list of the suites that you have already created.</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT3.png" alt="Test suites" width="600" height="502" style="border: 0px;" /></p>
<p>In this screenshot you can see two test suites that I've created. The second test "ZF2 Tutorial only" is the simplest suite possible as it contains a single page load within a single step. The top suite shows a more complex suite which hints at the complexity of the suites that you can create.</p>
<p>A suite is composed of one or more steps which are run in sequence. Each step can have multiple tests. If there are multiple test in the same step, then NLT will randomly pick one test for each run.<br />
In this suite I have four tests in step 1 which are a set of pages within the BRI website. Step 2 is the contact page and so this test suite is measuring visiting one of 4 pages within the site and then choosing to go to the contact page.</p>
<p>Creation of a new test suite is done via drag and drop:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT4.png" alt="Create new test suite" width="600" height="400" style="border: 0px;" /></p>
<p>You simply drag your green tests over to the list of steps on the right hand side. It's all quite easy. Rather weirdly, you can't reuse the same test in multiple steps, so if you're testing a cycle, then you need to duplicate the same test so that you can place it into two different steps. I haven't found a way to edit the steps within a test suite once created either, so make sure you get it right!</p>
<p>Once you have added tests to steps, you can then tell NLT to send data whilst load testing. This is useful for filling in forms or logging into the website, for instance. I haven't used this section as I haven't yet tested any pages with forms or requiring login.</p>
<p>Rather useful fully, you can change the domain that a test suite uses. This enables you to duplicate a test suite and then change the domain to test domain that's running on another server or using a different configuration which makes side-by-side testing a little easier.</p>
<h4>Calibration</h4>
<p>Once we have created a test suite, the next step is to calibrate it. NLT will not allow you to run a test suite before calibration, so don't forget this bit! Calibration is done from the test suites list page where there is a drop down box of operations you can do on each suite:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT5.png" alt="Operations on a test suite" width="600" height="181" style="border: 0px;" /></p>
<p>Simply pick Calibrate and press Go. NLT will then perform a single run over your suite and present the standard results page. Ideally, I would like to see this page look different from the standard results page as it's a calibration run, not a standard test and so I was slightly confused at this point. Also, whilst the test is running, you simply see one of those "spinning gifs" to let you know that something is happening. I ran into a bug in this section which resulted in the calibration run failing, but I was never notified on the page that an error had occurred.</p>
<p>The calibration results on my ZF2 tutorial page suite look like this:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT6.png" alt="Calibration results" width="600" height="410" style="border: 0px;" /></p>
<p>The intent of calibration is to provide a base-line to the NLT of the performance of the suite when there is no load. i.e. the idea is that this single run has provided an indication of the optimal conditions and we are expecting to be within 15% of this performance when testing under load.</p>
<h3>Running test suites</h3>
<p>Now that we have calibrated test suites, we can run some load tests and see what happens. In NLT parlance, we run test suites by pressing the Play button at which point the terminology changes to from play to execute. Simply select your test suite and press the Execute button. You are then presented with a form in order to set the run parameters:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT7.png" alt="Starting to execute a test" width="300" height="198" style="border: 0px;" /></p>
<p>There are three parameters you need to set:</p>
<table>
  <tr>
    <th>Concurrent&nbsp;Users</th>
    <td>How many users will hit your test suite. For steps with multiple tests, each user will randomly pick one to run.</td>
  </tr>
  <tr>
    <th>Total Executions</th>
    <td>How many times the suite will be run</td>
  </tr>
  <tr>
    <th>Spin up Delay</th>
    <td>Number of milliseconds before introducing the next user. A delay of 500 will results in 2 users per second being introduced to the load up to the total Concurrent users.</td>
  </tr>
</table>
<p>We set these numbers up to create the required load testing profile. I've been using 100 users at 250ms spin-up for 2000 total executions as this takes around 30 to 60 seconds to complete a run and seems a reasonable profile for my blog given its traffic levels.</p>
<p>Upon pressing execute, NLT will spin up a number of worker processes on its servers and then display a graph that updates every few seconds showing you what happening:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT10.png" alt="Graphical results" width="600" height="297" style="border: 0px;" /></p>
<p>As you can see in the screenshot above, you get this information:</p>
<ul>
  <li>A bar showing number of active requests (blue) on top of number of requests initiated.</li>
  <li>A line chart of median response time.</li>
</ul>
<p>The x-axis is in seconds. Hence the red bar chart shows the number of requests initiated during each second and the blue bar shows the number of requests that were still active at the end of the second. Hence a request that completed within a second is counted in the red bar, but not in the blue. Ideally, therefore we would like to see smaller blue bars than red bars and we definitely don't want to see blue bars getting bigger.</p>
<p>The green line shows us the average time it takes to server all requests in that second. Ideally, we want this number to be lower. Clearly, if there are any errors serving a request (e.g. an nginx bad gateway error), the rather fast failure time is not counted as it would bring the average down!</p>
<p>We can also view the data as a table:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT11.png" alt="Tabluar data" width="600" height="270" style="border: 0px;" /></p>
<p>Obviously, this is right at the start of the run, and so all look good. Clicking on a given run id will provide us with more information. This is a run that's later in the test:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT12.png" alt="Detailed results" width="600" height="336" style="border: 0px;" /></p>
<p>As you can see, the server was struggling now! The red background means that the request took more than 15% longer than the calibration run and the difference from calibration is shown in brackets in the Response Time column. In this particular run, the main HTML took 760ms to deliver which as 411ms longer than the calibration run. We're also struggling to serve images in a sensible time. This is clearly not ideal!</p>
<p>Looking at what's going on on the server whilst running a load test is also instructive. A good introduction to the server tools that are useful is <a href="http://h30565.www3.hp.com/t5/Feature-Articles/16-Linux-Server-Monitoring-Commands-You-Really-Need-To-Know/ba-p/1936">16 Linux server monitoring commands you really need to know</a> by Steven Vaughan-Nichols.</p>
<h3>Reviewing results</h3>
<p>Once you have a few runs under your belt, the Review page becomes useful. In this page we can see a list of all our previous runs and most importantly, we can edit the title of each run and give it a useful name. It would be nice to be able to store additional notes about each run though.</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLT14.png" alt="Previous runs" width="600" height="268" style="border: 0px;" /></p>
<p>Adding the title makes it much easier to remember why a given run was performed and I've found it useful.</p>
<h3>Using Natural Load Testing to improve performance</h3>
<p>The obvious first target for testing NLT, was my blog at akrabat.com. This is a simple WordPress blog which recently moved to a new server. I haven't been particularly worried about performance and don't really expect to ever be slash-dotted (or is it <a href="http://www.wolerized.com/blog/slashcal-dotted">Cal-dotted</a>, nowadays!) any time soon.</p>
<p>However, as I've done nothing to tune the system, this is a good time to see how it behaved. The first run produced these results:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLTp-1.png" alt="NLTp 1" width="600" height="250" style="border: 0px;" /></p>
<p>This isn't good! The only good sign was that none of the 2000 runs actually resulted in an error. A median response time around 1.5 seconds didn't sound good and the maximum run time was 13 seconds!</p>
<p>Something had to be done!</p>
<p>A little bit of investigating showed that neither APC or WP Super Cache was installed on the server. So I turned them on.</p>
<p>The effect of APC can be seen here:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLTp-2.png" alt="NLTp 2" width="600" height="245" style="border: 0px;" /></p>
<p>We now have an average response time of much less than 500ms which seems much saner. There were a number of very long requests of over 1 second though.</p>
<p>To see if I could improve this further, I then installed and enabled <a href="http://wordpress.org/extend/plugins/wp-super-cache/">WP Super Cache</a> in PHP mode and re-ran Natural Load Testing. The results were:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLTp-5.png" alt="NLTp 5" width="600" height="248" style="border: 0px;" /></p>
<p>Note that you need to be careful when comparing graphs as the axes are automatically scaled. Looking at the results with WP Super Cache was enabled, I can see that the response time display of the graph is much smoother. The tabular data backs this up as it shows that the vast majority of requests were taking less than 200ms with significantly fewer runs taking much longer. Also, the curve of the number of requests initiated vs request active at the end of each second is much smoother, which indicates that with WP Super Cache enabled, the server should be able to hold its own over a longer time period much more easily.</p>
<p>I tested this hypothesis by doing 5000 runs rather than the 2000 shown above. The result was:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2012-03-NLTp-6.png" alt="NLTp 6" width="600" height="241" style="border: 0px;" /></p>
<p>Again, the median response time is nicely under 150ms for most of the time, but we have more variance in the response time, with a couple of seconds where the median was significantly over 250ms.</p>
<p>On the whole, my investigations with NLT have made my blog much more responsive and more likely to be able to handle more traffic than before I started this process.</p>
<h3>Other thoughts</h3>
<p>Having walked though what Natural Load Testing does, I also need to point out that when using it, you can tell that this is a product still in beta! Incidentally, the WonderNetwork people have responded to my reports quickly, even if half the time it was to let me know that my idea or complaint was already <a href="http://blog.preinheimer.com/index.php?/archives/376-User-Feedback,-the-endless-cycle.html">on their list</a>!</p>
<p>Nearly all the issues I have with NLT at the moment are related to usability, which I'm sure will be ironed out over time. My "favourite" annoyance as noted above is on the create test suite page where the Save button is above the section where you set up the suite's steps. If you accidentally press Save after entering a title, then you find you can't actually add any tests to the steps! There's also no menu bar or easy way to get from one section to another. You very quickly learn to click on the NLT logo at the top which takes you to the home page.</p>
<p>It would also be good if NLT would allow me to store "execution profiles" so that I don't have to keep typing in that I want 100 users for 2000 total runs.</p>
<p>I would also like to see more aggregate results. In particular, I'd like to have stats on the response time for say the 50th and 95th percentile. I'd also like to graph these against multiple runs along with the run title so I can see how the site's performance changed over time. This then leads to the idea that it would be nice if I could schedule a load test once a month at 3am local time!</p>
<h3>Conclusion</h3>
<p>Natural Load Testing is the first product I've used that makes me actually want to do load testing. It makes it easy to run a specific load test and repeat exactly the same test as frequently as you need to. Tweaking the server to see the effect that any given change has becomes an interesting task and your websites can only benefit as you reduce and remove the bottle necks that you find.</p>
<p>On the whole, I'm quite impressed with Natural Load Testing and can see that it could turn into a very useful tool in the web developer's toolbox.</p>
<p>As I mentioned at the top, NLT is currently in private beta. If you want to get an invite, head over to the <a href="https://load.wondernetwork.com/beta/please/">sign up form</a> and fill in your details. You also <em>have</em> to read the thank you for signing up message!</p>
<p><a href="http://akrabat.com/?flattrss_redirect&amp;id=2218&amp;md5=3ed01d3802a16f1ccd490b39d445a0f0" title="Flattr" target="_blank"><img src="http://akrabat.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Wed, 04 Apr 2012 13:40:06 UT</pubDate>
            <guid>/entry/11/1176</guid>
        </item>
        <item>
            <title>Added to a feed: Developing A ZF2 Blog</title>
            <link>http://adamleach.co.uk/entry/developing-a-zf2-blog-11-1177.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1177">
<p>This post tells a story.</p>
<p>A long time ago, I set out to write my own blog platform. Yes, <a href="http://wordpress.org">WordPress</a> is a fine blogging platform, as is <a href="http://www.s9y.org/">Serendipity</a> (aka "s9y", and my previous platform). And yes, I know about <a href="http://habariproject.org">Habari</a>. And, for those of you skimming ahead, yes, I'm quite aware of <a href="http://github.com/mojombo/jekyll">Jekyll</a>, thank you anyways.</p>
<p>Why write something of my own? Well, of course, there's the fact that I'm a developer, and have control issues. Then there's also the fact that a blog is both a simple enough domain to allow easily experimenting with new technology and paradigms, while simultaneously providing a complex enough domain to expose non-trivial issues.</p>
<p>When I started this project, it was a technology-centered endeavor; I wanted to play with document databases such as <a href="http://couchdb.apache.org/">CouchDB</a> and <a href="http://www.mongodb.org/">MongoDB</a>, and with caching technologies like <a href="http://memcached.org">memcached</a> and <a href="http://redis.io">redis</a>.</p>
<p>Not long after I started, I also realized it was a great playground for me to prototype ideas for <a href="http://framework.zend.com/zf2">ZF2</a>; in fact, the original DI and MVC prototypes lived as branches of my blog. (My repository is still named "zf2sandbox" to this day, though it technically houses just my site.)</p>
<p>Over time, I had a few realizations. First, my <em>actual</em> blog was suffering. I wasn't taking the time to perform security updates, nor even normal upgrades, and was so far behind as to make the process non-trivial, particularly as I had a custom theme, and because I was proxying to my blog via a ZF app in order to facilitate a cohesive site look-and-feel. I needed to either sink time into upgrading, or finish my blog.</p>
<p>My second realization, however, was the more important one: I wanted a platform where I could write how <em>I</em> want to write. I am a keyboard-centric developer and computer user, and while I love the web, I hate typing in its forms. Additionally, my posts often take longer than a typical browser session -- which leaves me either losing my work in a GUI admin, or having to write first in my editor of choice, and then cut-and-paste it to the web forms. Finally, I want versions I can easily browse with standard diffing tools.</p>
<p>When it came down to it, my blog content is basically static. Occasionally, I'll update a post, but it's rare. Comments are really the only dynamic aspect of the blog... and what I had with s9y was not cutting it, as I was getting more spam than I could keep up with. New commenting platforms such as <a href="http://livefyre.com">Livefyre</a> and <a href="http://disqus.com">Disqus</a> provide more features than most blogging platforms I know, and provide another side benefit: because they are javascript-based, you can simply drop in a small amount of markup into your post <em>once</em> -- meaning your pages can be fully static!</p>
<p>Add these thoughts to the rise of static blogging platforms such as the aforementioned Jekyll, and I had a kernel of an idea: take the work I'd done already, and create a static blog generator.</p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 03 Apr 2012 13:45:00 UT</pubDate>
            <guid>/entry/11/1177</guid>
        </item>
        <item>
            <title>Added to a feed: Access view variables in another view model</title>
            <link>http://adamleach.co.uk/entry/access-view-variables-in-another-view-model-11-1178.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1178">
<p>Unlike Zend Framework 1, the view layer in Zend Framework 2 separates the variables assigned to each view model. This means that when you are in the layout view script, you don't automatically have access to variables that were assigned the the action's view model and vice versa.</p>
<h3>Accessing action variables in the layout</h3>
<p>Consider this controller code:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">IndexController&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">ActionController
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">indexAction</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;array(</span><span style="color: #DD0000">'myvar'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #DD0000">'test'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</span>
</pre>
<p>If you are in the layout.phtml, then to retrieve this value you do:</p>
<p><strong>layout.phtml:</strong></p>
<pre class="phpcode">
<span style="color: #0000BB">&lt;?php
$children&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">viewModel</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">getCurrent</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">getChildren</span><span style="color: #007700">();
</span><span style="color: #0000BB">$child&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$children</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">];
</span><span style="color: #0000BB">?&gt;
</span>&lt;!--&nbsp;some&nbsp;HTML&nbsp;--&gt;
<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">escape</span><span style="color: #007700">(</span><span style="color: #0000BB">$child</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">myvar</span><span style="color: #007700">);</span><span style="color: #0000BB">?&gt;
</span>
</pre>
<p>If you really want to make sure you collect the correct child view model, then you could iterate over <tt>$children</tt> and look for the child that has the correct <tt>captureTo</tt> name set. For the action's view model, this defaults to <tt>content</tt>:</p>
<p><strong>layout.phtml:</strong></p>
<pre class="phpcode">
<span style="color: #0000BB">&lt;?php
$children&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">viewModel</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">getCurrent</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">getChildren</span><span style="color: #007700">();
foreach(</span><span style="color: #0000BB">$children&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$child</span><span style="color: #007700">)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(</span><span style="color: #0000BB">$child</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">captureTo</span><span style="color: #007700">()&nbsp;==&nbsp;</span><span style="color: #DD0000">'content'</span><span style="color: #007700">)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</span><span style="color: #0000BB">?&gt;
</span>&lt;!--&nbsp;some&nbsp;HTML&nbsp;--&gt;
<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">escape</span><span style="color: #007700">(</span><span style="color: #0000BB">$child</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">myvar</span><span style="color: #007700">);</span><span style="color: #0000BB">?&gt;
</span>
</pre>
<h3>Accessing layout variables in the action view</h3>
<p>If you have assigned a variable to the layout's view model in, say, an event listener within <tt>Module.php</tt>:</p>
<p><strong>Module.php:</strong></p>
<pre class="phpcode"><span style="color: #0000BB">
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">public&nbsp;function&nbsp;</span><span style="color: #0000BB">onBootstrap</span><span style="color: #007700">(</span><span style="color: #0000BB">$e</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$application&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$e</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getParam</span><span style="color: #007700">(</span><span style="color: #DD0000">'application'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$viewModel&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$application</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getMvcEvent</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">getViewModel</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$viewModel</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">some_config_var&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'12345'</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}
</span>
</pre>
<p>This is how you access <tt>some_config_var</tt> in the action view:</p>
<p><strong>view/index/index.html:</strong></p>
<pre class="phpcode">
<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">escape</span><span style="color: #007700">(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">layout</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">some_config_var</span><span style="color: #007700">);&nbsp;</span><span style="color: #0000BB">?&gt;
</span>
</pre>
<p>Another, more long winded way is to use the <tt>getRoot()</tt> method on the <tt>viewModel</tt> view helper:</p>
<p><strong>view/index/index.html:</strong></p>
<pre class="phpcode">
<span style="color: #0000BB">&lt;?php
$layoutViewModel&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">viewModel</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">getRoot</span><span style="color: #007700">();&nbsp;
</span><span style="color: #0000BB">?&gt;
</span>&lt;!--&nbsp;Some&nbsp;HTML&nbsp;--&gt;
<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">escape</span><span style="color: #007700">(</span><span style="color: #0000BB">$layoutViewModel</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">some_config_var</span><span style="color: #007700">);&nbsp;</span><span style="color: #0000BB">?&gt;
</span>
</pre>
<h3>Setting configuration variables into the view</h3>
<p>It therefore follows that if you need to set a variable that could be accessed from any view script, it's easiest to set it into the layout's view model and then access it via the <tt>layout()</tt> view script. This is handy for view layer config variables that you want to store in your config files, such as the Google search API key.</p>
<p><strong>Application/config/module.config.php:</strong></p>
<pre class="phpcode">
<span style="color: #0000BB">&lt;?php
</span><span style="color: #007700">return&nbsp;array(
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'layout'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'google_search_api_key'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #DD0000">'1234567890'</span><span style="color: #007700">,
&nbsp;&nbsp;&nbsp;&nbsp;),
</span>
</pre>
<p><strong>Application/Module.php:</strong></p>
<pre class="phpcode"><span style="color: #0000BB">
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">public&nbsp;function&nbsp;</span><span style="color: #0000BB">onBootstrap</span><span style="color: #007700">(</span><span style="color: #0000BB">$e</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$application&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$e</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getParam</span><span style="color: #007700">(</span><span style="color: #DD0000">'application'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$config&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$e</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getParam</span><span style="color: #007700">(</span><span style="color: #DD0000">'config'</span><span style="color: #007700">);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$viewModel&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$application</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getMvcEvent</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">getViewModel</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$viewModel</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">config&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$config</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">layout</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}
</span>
</pre>
<p><strong>view/search/index.html:</strong></p>
<pre class="phpcode">
<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">layout</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">config</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">google_search_api_key</span><span style="color: #007700">;&nbsp;</span><span style="color: #0000BB">?&gt;
</span>
</pre>
<p><a href="http://akrabat.com/?flattrss_redirect&amp;id=2253&amp;md5=8a905fa9470e87ebdd62aafdcc8abc30" title="Flattr" target="_blank"><img src="http://akrabat.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 03 Apr 2012 12:15:31 UT</pubDate>
            <guid>/entry/11/1178</guid>
        </item>
        <item>
            <title>Added to a feed: Radio link and Nav Timing</title>
            <link>http://adamleach.co.uk/entry/radio-link-and-nav-timing-11-1179.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1179">
<p>In <a title="Making a mobile connection" href="http://www.stevesouders.com/blog/2011/09/21/making-a-mobile-connection/">Making a mobile connection</a> I describe how after just a few seconds of inactivity your mobile phone demotes the radio link to your carrier network. It typically takes 1-2 seconds to re-establish the radio link to full bandwidth capacity. This is a huge delay!</p>
<p>A few days ago I was discussing desktop vs. mobile page load times with some web performance wonks. These times were gathered from real users via the <a title="W3C Navigation Timing" href="http://www.w3.org/TR/navigation-timing/">W3C Nav Timing API</a>. We started chatting about why the mobile times were worse – slower connection speeds, less cache space, etc. – and it hit me that taking 2 seconds to re-establish the radio link might account for much of what makes mobile sites slower, especially in RUM (Real User Monitoring) vs. synthetic testing. And I wondered:</p>
<div style="padding-left: 30px;">
  <em>Does Nav Timing include the time to establish a radio link?</em>
</div>
<div style="padding-left: 30px; margin-bottom: 0.5em;">
  <em>If so, where is it accounted for?</em>
</div>
<p>After some initial testing it looks like the answers are:</p>
<div style="padding-left: 30px;">
  <em>Yes.</em>
</div>
<div style="padding-left: 30px; margin-bottom: 0.5em;">
  <em>It depends.</em>
</div>
<p>I started by creating a <a title="Nav Timing test page" href="http://stevesouders.com/navtiming.php">Nav Timing test page</a> that shows the values from Nav Timing. If you load the page you’ll see something like this. (Please look at page source to see how I calculate these conceptual time values.)</p>
<pre style="padding-left: 30px; margin-bottom: 0.5em;">total time = 239 ms
dns = 119 ms
connect = 16 ms
ttfb = 61 ms
HTML = 0 ms
frontend = 42 ms</pre>
<p><em>NOTE: Nav timing is available in Android 4. I’m not aware of any other mobile platform that has it, so you’ll need an Android 4 device to run these tests. You should close all/most currently running apps on your mobile device as they might be keeping the radio link alive in the background. On Android 4 this is done under Settings | Apps | Running. I had to stop Google Services.</em></p>
<p>You can determine if the radio link promotion delay occurs based on whether any of the times are greater than 2 seconds. Here’s a key:<em><br />
</em></p>
<dl>
  <dt style="font-weight: bold;">no 2 second times</dt>
  <dd>If all of the times are less than 2 seconds then the radio link was already active. You can create this result by loading the page multiple times in quick succession. All the times should be pretty fast because you have a radio link, the DNS resolution is cached, and you have a persistent connection to the web server.</dd>
  <dt style="font-weight: bold;">dns &gt; 2 seconds</dt>
  <dd>If you wait 10-20 seconds (and closed all background apps) the radio link gets demoted. At this point clicking on one of the buttons to open the test page on another domain will force a DNS lookup. Normally the DNS lookup should take a few hundred milliseconds, but if the radio link needs to be promoted the DNS time jumps to 2000+ milliseconds. This page is hosted on three different domains. If you use all three pages thus caching all three DNS resolutions, the only way I know of to clear the DNS cache is to power cycle the phone.</dd>
  <dt style="font-weight: bold;">connect &gt; 2 seconds</dt>
  <dd>If you allow the radio link to be demoted by waiting 10-20 seconds and reload the page (or click the button for the same page) you might see the connect time is greater than 2 seconds. This happens when the DNS is cached but there’s no persistent connection to the server. This is harder to reproduce – it depends on the browser’s policy for closing persistent connections.</dd>
  <dt style="font-weight: bold;">ttfb &gt; 2 seconds</dt>
  <dd>If the radio link is demoted, the DNS is cached, and there’s a persistent connection to the server you’ll see the time-to-first-byte (ttfb) is greater than 2 seconds. This is what happens most frequently when you load the same page multiple times with a 10-20 second gap in-between.</dd>
</dl>
<p>It’s important that developers focusing on performance be aware of the impact of radio link promotion on nav timing for mobile traffic so you don’t waste time solving the wrong problem: If you’re gathering RUM data via nav timing and see slow DNS times, you might think about investing in your DNS infrastructure – even though those slow DNS times might be caused by radio link promotion. Similarly, if you see long connection times it might not make sense to investigate how your servers manage persistent connections. And slow time-to-first-byte values may or may not indicate a backend app layer performance problem.</p>
<p>My website doesn’t generate enough mobile traffic to verify this theory, but I believe that websites with enough mobile nav timing data will see bimodal distributions of their timing data for dns, connection, and ttfb where the modes are ~2 seconds apart. If anyone has enough data (you know who you are) please take a look and comment below. It might be possible to develop heuristics that help us determine when radio link delays are having an impact. I’d love to get some stats on the percentage of page views that incur this delay.</p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 03 Apr 2012 04:33:16 UT</pubDate>
            <guid>/entry/11/1179</guid>
        </item>
        <item>
            <title>My Top 3 #lastfm Artists: deadmau5 (70), Knife Party (3) &amp;amp; Zedd (1) #music http://t. ...</title>
            <link>http://adamleach.co.uk/entry/my-top-3-lastfm-artists-deadmau5-70-knife-party-3--zedd-1-music--14-390.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">My Top 3 #lastfm Artists: deadmau5 (70), Knife Party (3) &amp; Zedd (1) #music <a href="http://t.co/9PBYJUMP" target="_blank">http://t.co/9PBYJUMP</a></div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Sun, 01 Apr 2012 22:02:52 UT</pubDate>
            <guid>/entry/14/390</guid>
        </item>
        <item>
            <title>Added to a feed: Returning JSON using the Accept header in ZF2</title>
            <link>http://adamleach.co.uk/entry/returning-json-using-the-accept-header-in-zf2-11-1180.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1180">
<p>Following yesterday's article on <a href="http://akrabat.com/zend-framework-2/returning-json-from-a-zf2-controller-action/">returning JSON from a ZF2 controller action</a>, <a href="http://twitter.com/lsmith">Lukas</a> suggested that I should also demonstrate how to use the Accept header to get JSON. So this is how you do it!</p>
<h3>Set up the JsonStrategy</h3>
<p>We set up the <tt>JsonStrategy</tt> as we did in <a href="http://akrabat.com/zend-framework-2/returning-json-from-a-zf2-controller-action/">returning JSON from a ZF2 controller action</a>.</p>
<h3>Return a ViewModel from the controller</h3>
<p>As we're letting the <tt>JsonStrategy</tt> intercede for us, we don't need to do anything special in our controller at all. In this case, we simply return a normal <tt>ViewModel</tt> for use by either the <tt>JsonRenderer</tt> or <tt>PhpRenderer</tt> as required:</p>
<p><strong>module/Application/src/Application/Controller/IndexController.php:</strong></p>
<pre class="phpcode">
<span style="color: #0000BB">&lt;?php

</span><span style="color: #007700">namespace&nbsp;</span><span style="color: #0000BB">ApplicationController</span><span style="color: #007700">;

use&nbsp;</span><span style="color: #0000BB">ZendMvcControllerActionController</span><span style="color: #007700">,
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">ZendViewModelViewModel</span><span style="color: #007700">;

class&nbsp;</span><span style="color: #0000BB">IndexController&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">ActionController
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">anotherAction</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$matches</span><span style="color: #007700">[]&nbsp;=&nbsp;array(</span><span style="color: #DD0000">'distance'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">10</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'playground'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;array(</span><span style="color: #DD0000">'a'</span><span style="color: #007700">=&gt;</span><span style="color: #0000BB">1</span><span style="color: #007700">));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$matches</span><span style="color: #007700">[]&nbsp;=&nbsp;array(</span><span style="color: #DD0000">'distance'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">20</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'playground'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;array(</span><span style="color: #DD0000">'a'</span><span style="color: #007700">=&gt;</span><span style="color: #0000BB">2</span><span style="color: #007700">));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$matches</span><span style="color: #007700">[]&nbsp;=&nbsp;array(</span><span style="color: #DD0000">'distance'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">30</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'playground'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;array(</span><span style="color: #DD0000">'a'</span><span style="color: #007700">=&gt;</span><span style="color: #0000BB">3</span><span style="color: #007700">));

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$result&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">ViewModel</span><span style="color: #007700">(array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'success'</span><span style="color: #007700">=&gt;</span><span style="color: #0000BB">true</span><span style="color: #007700">,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'results'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">$matches</span><span style="color: #007700">,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</span>
</pre>
<p>with our HTML view script:</p>
<p><strong>module/Application/view/index/another.phtml:</strong></p>
<pre class="phpcode">
<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">if&nbsp;(</span><span style="color: #0000BB">$success</span><span style="color: #007700">):&nbsp;</span><span style="color: #0000BB">?&gt;
</span>
&lt;h2&gt;Results&lt;/h2&gt;

&lt;ul&gt;
<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">foreach&nbsp;(</span><span style="color: #0000BB">$results&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$row</span><span style="color: #007700">):&nbsp;</span><span style="color: #0000BB">?&gt;
</span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;Distance:&nbsp;<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">escape</span><span style="color: #007700">(</span><span style="color: #0000BB">$row</span><span style="color: #007700">[</span><span style="color: #DD0000">'distance'</span><span style="color: #007700">]);</span><span style="color: #0000BB">?&gt;</span>m&lt;/li&gt;
<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">endforeach;&nbsp;</span><span style="color: #0000BB">?&gt;
</span>&lt;/ul&gt;

<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">endif;&nbsp;</span><span style="color: #0000BB">?&gt;
</span>
</pre>
<p>So if you set up a route and browse to it, you'll see a nicely rendered page.</p>
<h3>Retrieving the data as JSON</h3>
<p>To retrieve the data via JSON, we need a client where we can set the Accept header. We'll use <tt>curl</tt> for this test. When doing anything with APIs and testing, we head over to <a href="http://twitter.com/lornajane">LornaJane</a>'s blog for the <a href="http://www.lornajane.net/posts/2008/Curl-Cheat-Sheet">Curl Cheat Sheet</a> and use this command line:</p>
<pre>
curl -H "Accept: application/json" http://zf2test.dev/json/another
</pre>
<p>and you should see the output of:</p>
<pre>
{
  "content":{
    "success":true,
    "results": [
      {"distance":10,"playground":{"a":1}},
      {"distance":20,"playground":{"a":2}},
      {"distance":30,"playground":{"a":3}}
    ]
  }
}
</pre>
<p>(Formatted for readability - you get the result back on a single line from <tt>curl</tt>.)</p>
<p>This way you can use the same controllers for your HTML views and for returning JSON to those clients that can use it.</p>
<p><a href="http://akrabat.com/?flattrss_redirect&amp;id=2197&amp;md5=96ea55c57fca93c49f1f14e1104716a7" title="Flattr" target="_blank"><img src="http://akrabat.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Fri, 30 Mar 2012 08:16:28 UT</pubDate>
            <guid>/entry/11/1180</guid>
        </item>
        <item>
            <title>@treehouse has your site just stopped working. ...</title>
            <link>http://adamleach.co.uk/entry/treehouse-has-your-site-just-stopped-working--just-talking-to-my-boss-abo-14-389.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">@<a href="http://twitter.com/treehouse" target="_blank">treehouse</a> has your site just stopped working.  Just talking to my boss about signing up and it has stopped working</div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Thu, 29 Mar 2012 19:30:19 UT</pubDate>
            <guid>/entry/14/389</guid>
        </item>
        <item>
            <title>Added to a feed: Returning JSON from a ZF2 controller action</title>
            <link>http://adamleach.co.uk/entry/returning-json-from-a-zf2-controller-action-11-1181.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1181">
<p>The new view layer in Zend Framework 2 can be set up to return JSON rather than rendered HTML relatively easily. There are two steps to this:</p>
<h3>Set up the JsonStrategy</h3>
<p>Firstly we need to set up the view's <tt>JsonStrategy</tt> to check to a situation when returning JSON is required and then to render out JSON for us. The <tt>JsonStrategy</tt> will cause the <tt>JsonRenderer</tt> to be run in two situations:</p>
<ol>
  <li>The view model returned by the controller action is a <tt>JsonModel</tt></li>
  <li>The HTTP Accept header sent in the Request include "application/json"</li>
</ol>
<p>The enable the <tt>JsonStrategy</tt>, we simply attach it to the view's event manager with a reasonably high priority. This can be done in our Application's <tt>Module</tt> class. Firstly we create an <tt>onBootstrap()</tt> callback on the <tt>bootstrap</tt> event and then we implement <tt>onBootstrap()</tt> to attaché the <tt>JsonStrategy</tt>:</p>
<p><strong>module/Application/Module.php:</strong></p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">Module&nbsp;</span><span style="color: #007700">implements&nbsp;</span><span style="color: #0000BB">AutoloaderProvider
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">init</span><span style="color: #007700">(</span><span style="color: #0000BB">Manager&nbsp;$moduleManager</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$events&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">StaticEventManager</span><span style="color: #007700">::</span><span style="color: #0000BB">getInstance</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$events</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">attach</span><span style="color: #007700">(</span><span style="color: #DD0000">'bootstrap'</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'bootstrap'</span><span style="color: #007700">,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array(</span><span style="color: #0000BB">$this</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'onBootstrap'</span><span style="color: #007700">));
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">onBootstrap</span><span style="color: #007700">(</span><span style="color: #0000BB">Event&nbsp;$e</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$application&nbsp;&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$e</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getParam</span><span style="color: #007700">(</span><span style="color: #DD0000">'application'</span><span style="color: #007700">);&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;@var&nbsp;$application&nbsp;ZendMvcApplication&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$locator&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$application</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getLocator</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$view&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$locator</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">get</span><span style="color: #007700">(</span><span style="color: #DD0000">'ZendViewView'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$jsonStrategy&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$locator</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">get</span><span style="color: #007700">(</span><span style="color: #DD0000">'ZendViewStrategyJsonStrategy'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$view</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">events</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">attach</span><span style="color: #007700">(</span><span style="color: #0000BB">$jsonStrategy</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">100</span><span style="color: #007700">);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;more&nbsp;methods&nbsp;such&nbsp;as&nbsp;getConfig()&nbsp;and&nbsp;getAutoloaderConfig()
</span><span style="color: #007700">}
</span>
</pre>
<p>As you can see, in <tt>init()</tt> we grab the <tt>StaticEventManager</tt> to attach our <tt>onBootstrap()</tt> method to the <tt>bootstrap</tt> event. Then, within <tt>onBootstrap()</tt>, we grab the view and the <tt>JsonStrategy</tt> from the locator (via application) and attach the <tt>JsonStrategy</tt> to the view's <tt>events()</tt> event manager.</p>
<h3>Return a JsonModel from the controller action</h3>
<p>To send JSON to the client when the Accept header isn't application/json, we use a <tt>JsonModel</tt> in a controller action like this:</p>
<p><strong>module/Application/src/Application/Controller/IndexController.php:</strong></p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">namespace&nbsp;</span><span style="color: #0000BB">Application</span><span style="color: #007700"></span><span style="color: #0000BB">Controller</span><span style="color: #007700">;

use&nbsp;</span><span style="color: #0000BB">Zend</span><span style="color: #007700"></span><span style="color: #0000BB">Mvc</span><span style="color: #007700"></span><span style="color: #0000BB">Controller</span><span style="color: #007700"></span><span style="color: #0000BB">ActionController</span><span style="color: #007700">,
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Zend</span><span style="color: #007700"></span><span style="color: #0000BB">View</span><span style="color: #007700"></span><span style="color: #0000BB">Model</span><span style="color: #007700"></span><span style="color: #0000BB">ViewModel</span><span style="color: #007700">,
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Zend</span><span style="color: #007700"></span><span style="color: #0000BB">View</span><span style="color: #007700"></span><span style="color: #0000BB">Model</span><span style="color: #007700"></span><span style="color: #0000BB">JsonModel</span><span style="color: #007700">;

class&nbsp;</span><span style="color: #0000BB">IndexController&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">ActionController
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">indexAction</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$result&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">JsonModel</span><span style="color: #007700">(array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'some_parameter'&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #DD0000">'some&nbsp;value'</span><span style="color: #007700">,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'success'</span><span style="color: #007700">=&gt;</span><span style="color: #0000BB">true</span><span style="color: #007700">,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;));

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</span>
</pre>
<p>The output will now be JSON. Obviously, if you're sending JSON back based on the Accept header, then you can return a normal ViewModel.</p>
<p><a href="http://akrabat.com/?flattrss_redirect&amp;id=2174&amp;md5=d823f68ea36186881822028c47cfcf22" title="Flattr" target="_blank"><img src="http://akrabat.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Thu, 29 Mar 2012 09:55:48 UT</pubDate>
            <guid>/entry/11/1181</guid>
        </item>
        <item>
            <title>Added to a feed: Frontend SPOF in Beijing</title>
            <link>http://adamleach.co.uk/entry/frontend-spof-in-beijing-11-1182.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1182">
<p>This past December I contributed an article called <a href="http://calendar.perfplanet.com/2011/frontend-spof-in-beijing/">Frontend SPOF in Beijing</a> to PerfPlanet’s Performance Calendar. I hope that everyone who reads my blog also read the <a href="http://calendar.perfplanet.com/2011/">Performance Calendar</a> – it’s an amazing collection of web performance articles and gurus. But in case you don’t I’m cross-posting it here. I saw a great presentation from <a href="https://twitter.com/#!/patmeenan">Pat Meenan</a> about frontend SPOF and want to raise awareness around this issue. This post contains some good insights.</p>
<p>Make sure to read <a href="http://www.perfplanet.com/">PerfPlanet</a> – it’s a great aggregator of WPO blog posts.</p>
<p>Now – flash back to December 2011…</p>
<hr style="border-width: 2px; margin-bottom: 1em;" />
<p>I’m at <a href="http://velocity.oreilly.com.cn/2011/">Velocity China</a> in Beijing as I write this article for the <a href="http://calendar.perfplanet.com/2011/">Performance Calendar</a>. Since this is my second time to Beijing I was better prepared for the challenges of being behind the <a href="http://en.wikipedia.org/wiki/Golden_Shield_Project">Great Firewall</a>. I knew I couldn’t access popular US websites like <a href="http://www.google.com/">Google</a>, <a href="http://www.facebook.com/">Facebook</a>, and <a href="http://www.twitter.com/">Twitter</a>, but as I did my typical surfing I was surprised at how many other websites seemed to be blocked.</p>
<h2>Business Insider</h2>
<p>It didn’t take me long to realize the problem was <a href="http://www.stevesouders.com/blog/2010/06/01/frontend-spof/">frontend SPOF</a> – when a frontend resource (script, stylesheet, or font file) causes a page to be unusable. Some pages were completely blank, such as <a href="http://www.businessinsider.com/">Business Insider</a>:</p>
<div style="margin-bottom: 1em;">
  <a href="http://stevesouders.com/images/businessinsider-firefox.png"><img src="http://stevesouders.com/images/businessinsider-firefox.png" alt="" width="480" /></a> 
  <div style="text-align: center; font-weight: bold;">
    figure 1: The dreaded “blank white screen” due to a blocking Twitter script.
  </div>
</div>
<p>Firebug’s Net Panel shows that <code>anywhere.js</code> is taking a long time to download because it’s coming from <code>platform.twitter.com</code> – which is blocked by the firewall. Knowing that scripts block rendering of all subsequent DOM elements, we form the hypothesis that <code>anywhere.js</code> is being loaded in blocking mode in the HEAD. Looking at the <a href="http://stevesouders.com/analysis/greatfirewall/businessinsider-firefox.html">HTML source</a> we see that’s exactly what is happening:</p>
<pre class="codesample" style="width: 480px;">&lt;head&gt;
...
&lt;!-- Twitter Anywhere --&gt;
&lt;script src="https://platform.twitter.com/anywhere.js?id=ZV0...&amp;v=1" type="text/javascript"&gt;&lt;/script&gt;
&lt;!-- / Twitter Anywhere --&gt;
...
&lt;/head&gt;
...
&lt;body&gt;</pre>
<p>If <code>anywhere.js</code> had been loaded <a href="http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/">asynchronously</a> this wouldn’t happen. Instead, since <code>anywhere.js</code> is loaded the old way with <code>&lt;SCRIPT SRC=...</code>, it blocks all the DOM elements that follow which in this case is the entire BODY of the page. If we wait long enough the request for <code>anywhere.js</code> times out and the page begins to render. How long does it take for the request to timeout? Looking at the “after” screenshot of Business Insider we see it takes <em>1 minute and 15 seconds</em> for the request to timeout. That’s 1 minute and 15 seconds that the user is left staring at a blank white screen waiting for the Twitter script!</p>
<div style="margin-bottom: 1em;">
  <a href="http://stevesouders.com/images/businessinsider-firefox-after.png"><img src="http://stevesouders.com/images/businessinsider-firefox-after.png" alt="" width="480" /></a> 
  <div style="text-align: center; font-weight: bold;">
    figure 2: Business Insider finally renders after <em>1 minute 15 seconds</em>.
  </div>
</div>
<h2>CNET</h2>
<p><a href="http://www.cnet.com/">CNET</a> has a slightly different experience; the navigation header is displayed but the rest of the page is blocked from rendering:</p>
<div style="margin-bottom: 1em;">
  <a href="http://stevesouders.com/images/cnet-firefox.png"><img src="http://stevesouders.com/images/cnet-firefox.png" alt="" width="480" /></a> 
  <div style="text-align: center; padding: 1em 0; font-weight: bold;">
    figure 3: CNET rendering is blocked by ads from <code>eyewonder.com</code>.
  </div>
</div>
<p>Looking in Firebug we see that <code>wrapper.js</code> from <code>cdn.eyewonder.com</code> is “pending” – this must be another domain that’s blocked by the firewall. Based on where the rendering stops our guess is that the <code>wrapper.js</code> SCRIPT tag is immediately after the navigation header and is loaded in blocking mode thus preventing the rest of the page from rendering. The <a href="http://stevesouders.com/analysis/greatfirewall/cnet-firefox.html">HTML</a> confirms that this is indeed what’s happening:</p>
<pre class="codesample" style="width: 480px;">&lt;header&gt;
...
&lt;/header&gt;
&lt;script src="http://cdn.eyewonder.com/100125/771933/1592365/wrapper.js"&gt;&lt;/script&gt;
&lt;div id="rb_wrap"&gt;
&lt;div id="rb_content"&gt; &lt;div id="contentMain"&gt;</pre>
<h2>O’Reilly Radar</h2>
<p>Everyday I visit <a href="http://radar.oreilly.com/">O’Reilly Radar</a> to read <a href="http://radar.oreilly.com/nat/index.html">Nat Torkington’s</a> Four Short Links. Normally Nat’s is one of many stories on the Radar front page, but going there from Beijing shows a page with only one story:</p>
<div style="margin-bottom: 1em;">
  <a href="http://stevesouders.com/images/oreilly-radar-firefox.png"><img src="http://stevesouders.com/images/oreilly-radar-firefox.png" alt="" width="480" /></a> 
  <div style="text-align: center; padding: 1em 0; font-weight: bold;">
    figure 4: O’Reilly Radar rendering is blocked by Twitter widget.
  </div>
</div>
<p>At the bottom of this first story there’s supposed to be a Tweet button. This button is added by the <code>widgets.js</code> script fetched from <code>platform.twitter.com</code> which is blocked by the Great Firewall. This wouldn’t be an issue if <code>widgets.js</code> was fetched asynchronously, but sadly a peek at the <a href="http://stevesouders.com/analysis/greatfirewall/oreilly-radar-firefox.html">HTML</a> shows that’s not the case:</p>
<pre class="codesample" style="width: 480px;">&lt;a href="http://www.stevesouders.com/blog..."&gt;Comment&lt;/a&gt;
&amp;nbsp;|&amp;nbsp;
&lt;span class="social-counters"&gt;
&lt;span class="retweet"&gt;
&lt;a href="http://twitter.com/share" class="twitter-share-button"
   data-count="horizontal"
   data-url="http://radar.oreilly.com/2011/12/four-short-links-6-december-20-1.html"
   data-text="Four short links: 6 December 2011" data-via="radar"
   data-related="oreillymedia:oreilly.com"&gt;Tweet&lt;/a&gt;
&lt;script src="http://platform.twitter.com/widgets.js"
   type="text/javascript"&gt;&lt;/script&gt;
&lt;/span&gt;</pre>
<h2>The cause of frontend SPOF</h2>
<p>One possible takeaway from these examples might be that frontend SPOF is specific to Twitter and eyewonder and a few other 3rd party widgets. Sadly, frontend SPOF can be caused by any 3rd party widget, and even from the main website’s own scripts, stylesheets, or font files.</p>
<p>Another possible takeaway from these examples might be to avoid 3rd party widgets that are blocked by the Great Firewall. But the Great Firewall isn’t the only cause of frontend SPOF – it just makes it easier to reproduce. Any script, stylesheet, or font file that takes a long time to return has the potential to cause frontend SPOF. This typically happens when there’s an outage or some other type of failure, such as an overloaded server where the HTTP request languishes in the server’s queue for so long the browser times out.</p>
<p>The true cause of frontend SPOF is loading a script, stylesheet, or font file in a blocking manner. The table in my <a href="http://www.stevesouders.com/blog/2010/06/01/frontend-spof/">frontend SPOF</a> blog post shows when this happens. It’s really the website owner who controls whether or not their site is vulnerable to frontend SPOF. So what’s a website owner to do?</p>
<h2>Avoiding frontend SPOF</h2>
<p>The best way to avoid frontend SPOF is to load scripts asynchronously. Many popular 3rd party widgets do this by default, such as <a href="http://code.google.com/apis/analytics/docs/tracking/asyncTracking.html">Google Analytics</a>, <a href="https://developers.facebook.com/docs/reference/plugins/like/">Facebook</a>, and <a href="http://blog.meebo.com/?p=2956">Meebo</a>. Twitter also has an <a href="https://dev.twitter.com/docs/tweet-button">async snippet</a> for the Tweet button that O’Reilly Radar should use. If the widgets you use don’t offer an async version you can try Stoyan’s <a href="http://www.phpied.com/social-button-bffs/">Social button BFFs</a> async pattern.</p>
<p>Another solution is to wrap your widgets in an iframe. This isn’t always possible, but in two of the examples above the widget is eventually served in an iframe. Putting them in an iframe from the start would have avoided the frontend SPOF problems.</p>
<p>For the sake of brevity I’ve focused on solutions for scripts. Solutions for font files can be found in my <a href="http://www.stevesouders.com/blog/2009/10/13/font-face-and-performance/">@font-face and performance</a> blog post. I’m not aware of much research on loading stylesheets asynchronously. Causing too many reflows and <a href="http://bluerobot.com/web/css/fouc.asp/">FOUC</a> are concerns that need to be addressed.</p>
<h2>Call to action</h2>
<p><a href="http://www.businessinsider.com/">Business Insider</a>, <a href="http://www.cnet.com/">CNET</a>, and <a href="http://radar.oreilly.com/">O’Reilly Radar</a> all have visitors from China, and yet the way their pages are constructed delivers a bad user experience where most if not all of the page is blocked for more than a minute. This isn’t a P2 frontend JavaScript issue. <em>This is an outage.</em> If the backend servers for these websites took 1 minute to send back a response, you can bet the DevOps teams at Business Insider, CNET, and O’Reilly wouldn’t sleep until the problem was fixed. So why is there so little concern about frontend SPOF?</p>
<p>Frontend SPOF doesn’t get much attention – it definitely doesn’t get the attention it deserves given how easily it can bring down a website. One reason is it’s hard to diagnose. There are a lot of monitors that will start going off if a server response time exceeds 60 seconds. And since all that activity is on the backend it’s easier to isolate the cause. Is it that pagers don’t go off when clientside page load times exceed 60 seconds? That’s hard to believe, but perhaps that’s the case.</p>
<p>Perhaps it’s the way page load times are tracked. If you’re looking at worldwide medians, or even averages, and China isn’t a major audience your page load time stats might not exceed alert levels when frontend SPOF happens. Or maybe page load times are mostly tracked using synthetic testing, and those user agents aren’t subjected to real world issues like the Great Firewall.</p>
<p>One thing website owners can do is ignore frontend SPOF until it’s triggered by some future outage. A quick calculation shows this is a scary choice. If a 3rd party widget has a 99.99% uptime and a website has five widgets that aren’t async, the probability of frontend SPOF is 0.05%. If we drop uptime to 99.9% the probability of frontend SPOF climbs to 0.5%. Five widgets might be high, but remember that “third party widget” includes ads and metrics. Also, the website’s own resources can cause frontend SPOF which brings the number even higher. The average website today contains <a href="http://httparchive.org/trends.php#bytesJS&amp;reqJS">14 scripts</a> any of which could cause frontend SPOF if they’re not loaded async.</p>
<p>Frontend SPOF is a real problem that needs more attention. Website owners should use async snippets and patterns, monitor real user page load times, and look beyond averages to 95th percentiles and standard deviations. Doing these things will mitigate the risk of subjecting users to the dreaded blank white page. A chain is only as strong as its weakest link. What’s your website’s weakest link? There’s a lot of focus on backend resiliency. I’ll wager your weakest link is on the frontend.</p>
<hr style="border-width: 2px; margin-bottom: 1em;" />
<p>[Originally posted as part of PerfPlanet's <a href="http://calendar.perfplanet.com/2011/frontend-spof-in-beijing/">Performance Calendar 2011</a>.]</p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Wed, 28 Mar 2012 20:35:46 UT</pubDate>
            <guid>/entry/11/1182</guid>
        </item>
        <item>
            <title>Added to a feed: Cache compressed? or uncompressed?</title>
            <link>http://adamleach.co.uk/entry/cache-compressed-or-uncompressed-11-1183.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1183">
<p>My previous blog post, <a href="http://www.stevesouders.com/blog/2012/03/22/cache-them-if-you-can/">Cache them if you can</a>, suggests that current cache sizes are too small – especially on mobile.</p>
<p>Given this concern about cache size a relevant question is:<em></em></p>
<p style="padding-left: 30px;"><em>If a response is compressed, does the browser save it compressed or uncompressed?</em></p>
<p>Compression typically reduces responses by 70%. This means that a browser can cache 3x as many compressed responses if they’re saved in their compressed format.</p>
<p>Note that not all responses are compressed. Images make up the largest number of resources but shouldn’t be compressed. On the other hand, HTML documents, scripts, and stylesheets should be compressed and account for <a href="http://httparchive.org/trends.php#bytesTotal&amp;reqTotal">30% of all requests</a>. Being able to save 3x as many of these responses to cache could have a significant impact on cache hit rates.</p>
<p>It’s difficult and time-consuming to determine whether compressed responses are saved in compressed format. I created this <a href="http://stevesouders.com/tests/cache-gzip.php">Caching Gzip Test</a> page to help determine browser behavior. It has two 200 KB scripts – one is compressed down to ~148 KB and the other is uncompressed. (Note that this file is random strings so the compression savings is only 25% as compared to the typical 70%.) After clearing the cache and loading the test page if the total cache disk size increases ~348 KB it means the browser saves compressed responses as compressed. If the total cache disk size increases ~400 KB it means compressed responses are saved uncompressed.</p>
<p>The challenging part of this experiment is finding where the cache is stored and measuring the response sizes. Firefox, Chrome, and Opera save responses as files and were easy to measure. For IE on Windows I wasn’t able to access the individual cache files (admin permissions?) but was able to measure the sizes based on the properties of the Temporary Internet Files folder. Safari saves all responses in Cache.db. I was able to see the incremental increase by modifying the experiment to be two pages: the <a href="http://stevesouders.com/tests/cache-gzip1.php">compressed response</a> and the <a href="http://stevesouders.com/tests/cache-gzip2.php">uncompressed response</a>. You can see the cache file locations and full details in the <a href="http://stevesouders.com/tests/cache-gzip-results.php">Caching Gzip Test Results page</a>.</p>
<p>Here are the results for top desktop browsers:</p>
<table style="margin-left: 20px;" border="1" cellspacing="0" cellpadding="0">
  <tbody>
  <tr>
    <th style="background: #DDD; padding: 4px 16px; vertical-align: middle;">Browser</th>
    <th style="background: #DDD; padding: 4px 16px; vertical-align: middle;">Compressed responses<br />
    cached compressed?</th>
    <th style="background: #DDD; padding: 4px 16px; vertical-align: middle;">max cache size</th>
  </tr>
  <tr>
    <td style="padding-left: 8px;">Chrome 17</td>
    <td style="text-align: center;">yes</td>
    <td style="text-align: right; padding-right: 1em;"><a href="https://plus.google.com/103382935642834907366/posts/XRekvZgdnBb">320 MB</a>*</td>
  </tr>
  <tr>
    <td style="padding-left: 8px;">Firefox 11</td>
    <td style="text-align: center;">yes</td>
    <td style="text-align: right; padding-right: 1em;">850 MB*</td>
  </tr>
  <tr>
    <td style="padding-left: 8px;">IE 8</td>
    <td style="text-align: center;">no</td>
    <td style="text-align: right; padding-right: 1em;"><a href="http://blogs.msdn.com/b/ie/archive/2011/03/17/internet-explorer-9-network-performance-improvements.aspx">50 MB</a></td>
  </tr>
  <tr>
    <td style="padding-left: 8px;">IE 9</td>
    <td style="text-align: center;">no</td>
    <td style="text-align: right; padding-right: 1em;"><a href="http://blogs.msdn.com/b/ie/archive/2011/03/17/internet-explorer-9-network-performance-improvements.aspx">250 MB</a></td>
  </tr>
  <tr>
    <td style="padding-left: 8px;">Safari 5.1.2</td>
    <td style="text-align: center;">no</td>
    <td style="text-align: right; padding-right: 1em;">unknown</td>
  </tr>
  <tr>
    <td style="padding-left: 8px;">Opera 11</td>
    <td style="text-align: center;">yes</td>
    <td style="text-align: right; padding-right: 1em;">20 MB</td>
  </tr>
  </tbody>
</table>
<p style="font-size: 0.9em;">* Chrome and Firefox cache size is a percentage of available disk space. Chrome is capped at 320 MB. I don’t know what Firefox’s cap is; on my laptop with 50 GB free the cache size is 830 MB.</p>
<p>We see that Chrome 17, Firefox 11, and Opera 11 store compressed responses in compressed format, while IE 8&amp;9 and Safari 5 save them uncompressed. IE 8&amp;9 have smaller cache sizes, so the fact that they uncompress responses before caching further reduces the number of responses that can be cached.</p>
<p>What’s the best choice? It’s possible that reading cached responses is faster if they’re already uncompressed. That would be a good next step to explore. I wouldn’t prejudge IE’s choice when it comes to performance on Windows. But it’s clear that saving compressed responses in compressed format increases the number of responses that can be cached, and this increases cache hit rates. What’s even clearer is that browsers don’t agree on the best answer. Should they?</p>
<p> </p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 27 Mar 2012 23:05:38 UT</pubDate>
            <guid>/entry/11/1183</guid>
        </item>
        <item>
            <title>Added to a feed: Slides: MySQL 5.6 Global Transaction Identifier and PECL/mysqlnd_ms for ...</title>
            <link>http://adamleach.co.uk/entry/slides-mysql-56-global-transaction-identifier-and-peclmysqlndms-for-ses-11-1184.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1184">
<p>Why do we have to bother about built-in GTID support in MySQL 5.6 at all? Sure, it is a tremendous step forward for a lazy primary copy system like MySQL Replication. Period. GTIDs make server-side failover easier (<a href="http://www.slideshare.net/nixnutz/mysql-56-global-transaction-identifier-use-case-failover">slides</a>). And, load balancer, including <a href="http://php.net/mysqlnd_ms">PECL/mysqlnd_ms</a> as an example of a driver integrated load balancer, can use them to provide session consistency. Please, see the slides. But&#8230;</p>
<p style="text-align: center;"></p>
<div style="width:425px">
  <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/nixnutz/mysql-56-global-transaction-ids-use-case-session-consistency" title="MySQL 5.6 Global Transaction IDs - Use case: (session) consistency" target="_blank">MySQL 5.6 Global Transaction IDs - Use case: (session) consistency</a></strong> <br />
  <div style="padding:5px 0 12px">
    View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> on <a href="http://www.slideshare.net/nixnutz" target="_blank">MySQL and mysqlnd</a>
  </div>
</div>
<p>&#8230; the primary remains a single point of failure. GTIDs can be described as cluster-wide transaction counters generated on the master. In case of a master failure, the slave that has replicated the highest transaction counter shall be promoted to become the master. Its the most current slave. Failover made easy - no doubt! Adequately deployed, you should reach very reasonable availability.</p>
<h3>Know the limits of replicated systems</h3>
<p>A multi-master (update anywhere) design does not have a single point of failure. But among the biggest is scaling a multi-master solution. <a href="http://en.wikipedia.org/wiki/Jim_Gray_%28computer_scientist%29">Jim Gray</a> and Pat Helland concluded 1996 in &quot;<a href="http://research.microsoft.com/apps/pubs/default.aspx?id=68247">The Dangers of Replication and a Solution</a>&quot;: <cite>Update anywhere-anytime-anyway transactional replication has unstable behavior as the workload scales up: a ten-fold increase in nodes and traffic gives a thousand fold increase in deadlocks or reconciliations.</cite>. N^3 - buuuhhhh, anything worse than linear scale is not appreciated. Guess what: Microsoft SQL Azure is using primary copy combined with partitioning.</p>
<p><a id="more-353"></a></p>
<p>In practice things are not that bad, particulary not for a small number of nodes and recent algorithms. For example, <a href="http://dev.mysql.com/tech-resources/articles/mysql-cluster-7.2-ga.html">MySQL Cluster</a> (<a href="http://dev.mysql.com/news-and-events/web-seminars/display-695.html">related webinar on March 29</a>) is a true multi-master solution - even eager/synchronous. To overcome the write-scale limitations it has built-in partitioning (sharding). The two classical scale-out solutions - replication and partitioning - are combined in one product. If you want extreme performance and are ready to pay for the costs of partitioning&#8230; try it.</p>
<h3>Anything to learn from the NoSQL kids on the block?</h3>
<p>Some other kids offer relaxed eventual consistency just as MySQL Replication does. Sometimes the <a href="http://en.wikipedia.org/wiki/CAP_theorem">CAP theorem</a> is cited as an excuse for it . Some leave conflict resolution, even conflict detection to the application developer . A massively scalabale, high available, synchronous update anywhere solution with built-in conflict resolution - the big thing we all dream of - is hard to create.</p>
<h3>In the meanwhile&#8230; - maybe custer-aware APIs</h3>
<p>While we all wait for the one-fits-all solution, there is something we can do. We can start to tell our load balancers precisely what we need and request no higher level of service than needed. Consistency - as in CAP - is one aspect of service quality. We should start to have cluster-aware APIs abstracting the details of replication architectures. Then, our load balancers, including PECL/mysqlnd_ms can hide everything that makes working with a cluster complicated (connection pooling, request splitting and redirection, failover, node selection, load distribution, &#8230;). Also, vendors can start to play with consistency to improve performance without messing up application logic.</p>
<p>Below is how you use the PECL/mysqlnd_ms 1.2+ function <code>mysqlnd_ms_set_qos()</code> to switch between eventual consistency (stale data allowed) and session concistency (read-your-writes). MySQL Replication details hidden behind a function call.</p>
<p></p>
<pre>
<code>
$mysqli = new mysqli(&quot;myapp&quot;, &quot;username&quot;, &quot;password&quot;, &quot;database&quot;);
if (!$mysqli)
  /* Of course, your error handling is nicer... */
  die(sprintf(&quot;[%d] %sn&quot;, mysqli_connect_errno(), mysqli_connect_error()));
	
/* read-write splitting: master used */
if (!$mysqli-&gt;query(&quot;INSERT INTO orders(order_id, item) VALUES (1, 'christmas tree, 1.8m')&quot;)) {
   /* Please use better error handling in your code */
  die(sprintf(&quot;[%d] %sn&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
}
	
/* Request session consistency: read your writes */
if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_SESSION))
  die(sprintf(&quot;[%d] %sn&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
	
/* Plugin picks a node which has the changes, here: master */
if (!$res = $mysqli-&gt;query(&quot;SELECT item FROM orders WHERE order_id = 1&quot;))
  die(sprintf(&quot;[%d] %sn&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
	
var_dump($res-&gt;fetch_assoc());
	
/* Back to eventual consistency: stale data allowed */
if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL))
  die(sprintf(&quot;[%d] %sn&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
	
/* Plugin picks any slave, stale data is allowed */
if (!$res = $mysqli-&gt;query(&quot;SELECT item, price FROM specials&quot;))
  die(sprintf(&quot;[%d] %sn&quot;, $mysqli-&gt;errno, $mysqli-&gt;error));
</code>
</pre>
<h3>GTID for clients? Buzz alarm!</h3>
<p>PECL/mysqlnd_ms 1.3 does not bring any ground breaking changes with regards to consistency or GTIDs. It can now either use the driver built-in GTID emulation (1.2+) or the server-side GTID feature (1.3+, MySQL 5.6) for session consistency. That&#8217;s all. I confess, the slide title is pure buzz. But in every tale is some truth.</p>
<h3>Cluster-aware APIs and better load balancer? Follow up!</h3>
<p>I&#8217;m convinced that good load balancers can make application developers life much easier. Read-your-writes and session consistency is an example how new API calls may come handy. Transparently replacing remote slave accesses with client-side cache accesses (coming with 1.3) is an example how load balancers can optimize overall cluster performance.</p>
<p>Whoever designs a replication solution in 2012 should include the load balancer into his considerations&#8230; - even for multi-master.</p>
<p>Happy hacking!</p>
<p style="text-align: center;"><a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" alt="Follow me on Twitter" style="text-align: middle;" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 27 Mar 2012 14:19:57 UT</pubDate>
            <guid>/entry/11/1184</guid>
        </item>
        <item>
            <title>Added to a feed: Automatic Apache vhosts</title>
            <link>http://adamleach.co.uk/entry/automatic-apache-vhosts-11-1185.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1185">
<p>One thing that I've wanted to implement for a while now is automatic vhosts on my dev box. The idea is that I want to drop a folder into a directory and have it automatically turned into a vhost for me accessible at <tt>http://<em>foldername</em>.dev</tt>. It turns out that this isn't nearly as hard as expected which is usually the case with things that I've been putting off!</p>
<p>This is how to do it.</p>
<h4>Apache configuration</h4>
<p>The Apache magic is in an extension called <tt><a href="http://httpd.apache.org/docs/2.2/mod/mod_vhost_alias.html">mod_vhost_alias</a></tt> which you may need to enable in your <tt>httpd.conf</tt> file.</p>
<p>You can then set up the <tt>VirtualHost</tt> wherever you keep such things. On a stock OS X, the <tt>extras/httpd-vhosts.conf</tt> file is used.</p>
<p>Add the following to the bottom:</p>
<pre>
&lt;Virtualhost *:80&gt;
    VirtualDocumentRoot &quot;/www/dev/%1/public&quot;
    ServerName vhosts.dev
    ServerAlias *.dev
    UseCanonicalName Off
    LogFormat &quot;%V %h %l %u %t &quot;%r&quot; %s %b&quot; vcommon
    ErrorLog &quot;/www/dev/vhosts-error_log&quot;
    &lt;Directory &quot;/www/dev/*&quot;&gt;
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        Allow from all
    &lt;/Directory&gt;
&lt;/Virtualhost&gt;
</pre>
<p>In the <tt>VirtualHost</tt> configuration, I have used the <tt>ServerAlias</tt> and <tt>VirtualDocumentRoot</tt> directives to map <tt>http://<em>foldername</em>.dev</tt> to the directory <tt>/www/dev/<em>foldername</em>/public</tt>. Hence, any folder that I place in <tt>/www/dev</tt> will have its own virtual host. Alter these appropriately for your set-up.</p>
<p>Don't forget to restart Apache.</p>
<p>Unfortunately, the computer hasn't a clue how to handle http://foldername.dev and the obvious solution is to run a local DNS server. Another solution is to use a PAC file.</p>
<h4>DNS server configuration</h4>
<p>This is easy enough with <a href="http://www.thekelleys.org.uk/dnsmasq/doc.html">dnsmasq</a>. On OS X, use <a href="http://mxcl.github.com/homebrew/">Homebrew</a> to install like this: <tt>brew install dnsmasq</tt>. On Linux, use your package manager; on Windows, you're own your own!</p>
<p>Note that on OS X, you should set it to start up automatically using launchd as noted in the instructions after installation. You also need to copy the configuration file to <tt>/etc</tt> using: <tt>cp /usr/local/Cellar/dnsmasq/2.57/dnsmasq.conf.example /usr/local/etc/dnsmasq.conf</tt> (or whatever the latest version number is). on Linux, I would guess that your package manager provides a dnsmasq.conf file in <tt>/etc</tt> or <tt>/etc/dnsmasq</tt>.</p>
<p>Next, edit <tt>dnsmasq.conf</tt> file and added the following lines to the bottom:</p>
<pre>
listen-address=127.0.0.1
address=/.dev/127.0.0.1
</pre>
<h4>Add the name server to your network configuration</h4>
<p>On OS X, Go to <em>System Preferences</em> -&gt; <em>Network</em> -&gt; <em>{Wifi or Ethernet}</em> -&gt; <em>Advanced&hellip;</em> -&gt; <em>DNS</em> and click on + button at the bottom of the left hand panel and add <strong>127.0.0.1</strong> to the list of DNS servers. Drag 127.0.0.1 at the top of the list.</p>
<p>On Linux, you should use the appropriate GUI tools for your distribution or potentially edit <tt>etc/dhcp/dhclient.conf</tt> and uncomment the <tt>domain-name-servers 127.0.0.1;</tt> on line 20 (on Ubuntu).</p>
<p>Restart dnsmasq and you should now be able to execute <tt>host test.dev</tt> on the command line and see <tt>127.0.0.1</tt> as the resultant address.</p>
<h4>Alternative to DNS server: PAC file</h4>
<p>Since publishing this article, <a href="http://twitter.com/inxilpro">Chris Morell</a> pointed out that you can also use PAC files rather than install a DNS server. Details are on his <a href="http://cmorrell.com/webdev/automatic-virtual-hosts-w-proxy-auto-config-768">blog post</a>.</p>
<h4>Check it works</h4>
<p>Create a directory called <tt>test</tt> in your <tt>dev</tt> directory. Within <tt>test</tt>, create <tt>public/index.php</tt> and within <tt>index.php</tt> add some code to prove it works. e.g. <tt>&lt; ;?php echo "Hello World"; ?&gt;;</tt></p>
<p>If you navigate to http://test.dev, you should see "Hello World" displayed.</p>
<h4>Caveats</h4>
<p>A couple of caveats:</p>
<ul>
  <li><tt>DOCUMENT_ROOT</tt> is not /www/dev/test as you'd expect. Instead it is the global document root. See <a href="https://gist.github.com/2208990">this gist</a> for a neat way to solve this using a prepend file.</li>
  <li>If you use mod_rewrite, then you'll need a <tt>RewriteBase /</tt> in your <tt>.htaccess</tt> file. Alternatively, you can change the <tt>Directory</tt> section of your vhost to do the rewriting for you if all your projects are alike. Something like this should work: 
  <pre>
    &lt;Directory &quot;/www/dev/*&quot;&gt;
        Options Indexes FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        Allow from all

        RewriteEngine On
        RewriteBase /
        RewriteCond %{REQUEST_FILENAME} -s [OR]
        RewriteCond %{REQUEST_FILENAME} -l [OR]
        RewriteCond %{REQUEST_FILENAME} -d
        RewriteRule ^.*$ - [NC,L]
        RewriteRule ^.*$ index.php [NC,L]
    &lt;/Directory&gt;
</pre>
  </li>
</ul>
<h4>All done</h4>
<p>That's it. You can now create as many projects as you like without having to worry about setting up new virtual hosts or modifying you hosts file!</p>
<p><a href="http://akrabat.com/?flattrss_redirect&amp;id=2158&amp;md5=07bcda0d15dbd1eac3d0f82a381ad628" title="Flattr" target="_blank"><img src="http://akrabat.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Mon, 26 Mar 2012 07:24:50 UT</pubDate>
            <guid>/entry/11/1185</guid>
        </item>
        <item>
            <title>My Top 3 #lastfm Artists: deadmau5 (74), Knife Party (9) &amp;amp;amp; deadmau5 &amp;amp;amp; ...</title>
            <link>http://adamleach.co.uk/entry/my-top-3-lastfm-artists-deadmau5-74-knife-party-9-amp-deadmau5-am-14-388.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">My Top 3 #lastfm Artists: deadmau5 (74), Knife Party (9) &amp;amp; deadmau5 &amp;amp; Kaskade (2) #music <a href="http://t.co/9PBYJUMP" target="_blank">http://t.co/9PBYJUMP</a></div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Sun, 25 Mar 2012 23:12:24 UT</pubDate>
            <guid>/entry/14/388</guid>
        </item>
        <item>
            <title>@BadgerGP @Lotus_F1Team have got photos on their blog http://t.co/LwgZOYw8</title>
            <link>http://adamleach.co.uk/entry/badgergp-lotusf1team-have-got-photos-on-their-blog-httptcolwgzoyw8-14-387.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">@<a href="http://twitter.com/BadgerGP" target="_blank">BadgerGP</a> @<a href="http://twitter.com/Lotus_F1Team" target="_blank">Lotus_F1Team</a> have got photos on their blog <a href="http://t.co/LwgZOYw8" target="_blank">http://t.co/LwgZOYw8</a></div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Sat, 24 Mar 2012 14:50:40 UT</pubDate>
            <guid>/entry/14/387</guid>
        </item>
        <item>
            <title>Added to a feed: FlossUK and Puppetcamp Edinburgh</title>
            <link>http://adamleach.co.uk/entry/flossuk-and-puppetcamp-edinburgh-11-1186.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1186">
<p>I've just finished presenting my talk on how I currently work on Puppet modules at Puppetcamp here in Edinburgh where I've been for the week talking on both FlossUK 2012 and Puppetcamp.</p>
<div style="width:425px">
  <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/KrisBuytaert/7-tools-for-your-devops-stack" title="7 tools for your devops stack" target="_blank">7 tools for your devops stack</a></strong> <br />
  <div style="padding:5px 0 12px">
    View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/KrisBuytaert" target="_blank">Kris Buytaert</a>
  </div>
</div>
<p>Earlier this week I opened FlossUK 2012 with my talk on 7 tools for your devops stack</p>
<div style="width:425px">
  <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/KrisBuytaert/how-ihackonpuppetmodules" title="How I hack on puppet modules" target="_blank">How I hack on puppet modules</a></strong> <br />
  <div style="padding:5px 0 12px">
    View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/KrisBuytaert" target="_blank">Kris Buytaert</a>
  </div>
</div>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Fri, 23 Mar 2012 14:49:47 UT</pubDate>
            <guid>/entry/11/1186</guid>
        </item>
        <item>
            <title>Added to a feed: Cache them if you can</title>
            <link>http://adamleach.co.uk/entry/cache-them-if-you-can-11-1187.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1187">
<p style="padding-left: 30px;"><em>“The fastest HTTP request is the one not made.”</em></p>
<p>I always smile when I hear a web performance speaker say this. I forget who said it first, but I’ve heard it numerous times at conferences and meetups over the past few years. It’s true! Caching is critical for making web pages faster. I’ve written extensively about caching:</p>
<ul>
  <li><a href="http://www.stevesouders.com/blog/2010/04/26/call-to-improve-browser-caching/">Call to improve browser caching</a></li>
  <li><a href="http://www.stevesouders.com/blog/2011/06/28/lack-of-caching-for-iphone-home-screen-apps/">(lack of) Caching for iPhone Home Screen Apps</a></li>
  <li><a href="http://www.stevesouders.com/blog/2010/07/23/redirect-caching-deep-dive/">Redirect caching deep dive</a></li>
  <li><a href="http://www.stevesouders.com/blog/2010/07/12/mobile-cache-file-sizes/">Mobile cache file sizes</a></li>
  <li><a href="http://www.stevesouders.com/blog/2011/10/03/improving-app-cache/">Improving app cache</a></li>
  <li><a href="http://www.stevesouders.com/blog/2011/03/28/storager-case-study-bing-google/">Storager case study: Bing, Google</a></li>
  <li><a href="http://www.stevesouders.com/blog/2011/09/26/app-cache-localstorage-survey/">App cache &amp; localStorage survey</a></li>
  <li><a href="http://www.stevesouders.com/blog/2011/04/18/http-archive-max-ag/">HTTP Archive: max-age</a></li>
</ul>
<p>Things are getting better – but not quickly enough. The chart below from the <a href="http://httparchive.org/trends.php?s=intersection&amp;minlabel=Feb+11+2011&amp;maxlabel=Feb+15+2012#maxageNull">HTTP Archive</a> shows that the percentage of resources that are cacheable has increased 10% during the past year (from 42% to 46%). Over that same time the number of requests per page has increased 12% and total transfer size has increased 24% (<a href="http://httparchive.org/trends.php?s=intersection&amp;minlabel=Feb+11+2011&amp;maxlabel=Feb+15+2012#bytesTotal&amp;reqTotal">chart</a>).</p>
<p><a href="http://httparchive.org/trends.php?s=intersection&amp;minlabel=Feb+11+2011&amp;maxlabel=Feb+15+2012#maxageNull"><img class="aligncenter" title="Caching trends" src="http://stevesouders.com/images/ha-caching-trends-20120215.png" alt="" width="480" height="240" /></a></p>
<p>Perhaps it’s hard to make progress on caching because the problem doesn’t belong to a single group – responsibility spans website owners, third party content providers, and browser developers. One thing is certain – we have to do a better job when it comes to caching. <em></em></p>
<p>I’ve gathered some compelling statistics over the past few weeks that illuminate problems with caching and point to some next steps. Here are the highlights:</p>
<ul>
  <li>55% of resources don’t specify a max-age value</li>
  <li>46% of the resources without any max-age remained unchanged over a 2 week period</li>
  <li>some of the most popular resources on the Web are only cacheable for an hour or two</li>
  <li>40-60% of daily users to your site don’t have your resources in their cache</li>
  <li>30% of users have a full cache</li>
  <li>for users with a full cache, the median time to fill their cache is 4 hours of active browsing</li>
</ul>
<p>Read on to understand the full story.</p>
<h3>My kingdom for a max-age header</h3>
<p>Many of the caching articles I’ve written address issues such as size &amp; space limitations, bugs with less common HTTP headers, and outdated purging logic. These are critical areas to focus on. But the basic function of caching hinges on websites specifying caching headers for their resources. This is typically done using max-age in the Cache-Control response header. This example specifies that a response can be read from cache for 1 year:</p>
<p style="padding-left: 30px;"><code>Cache-Control: max-age=31536000</code></p>
<p>Since you’re reading this blog post you probably already use max-age, but the following chart from the <a href="http://httparchive.org/interesting.php?a=All&amp;l=Feb%2015%202012#max-age">HTTP Archive</a> shows that <strong>55% of resources don’t specify a max-age value</strong>. This translates to 45 of the average website’s 81 resources needing a HTTP request even for repeat visits.</p>
<p style="text-align: center;"><a href="http://httparchive.org/interesting.php?a=All&amp;l=Feb%2015%202012#max-age"><img class="aligncenter" title="max-age distribution" src="http://stevesouders.com/images/ha-maxage-20120215.png" alt="" width="480" height="322" /></a></p>
<h3>Missing max-age != dynamic</h3>
<p>Why do 55% of resources have no caching information? Having looked at caching headers across thousands of websites my first guess is lack of awareness – many website owners simply don’t know about the benefits of caching. An alternative explanation might be that many resources are dynamic (JSON, ads, beacons, etc.) and <em>shouldn’t</em> be cached. Which is the bigger cause – lack of awareness or dynamic resources? Luckily we can quantify the dynamicness of these uncacheable resources using data from the HTTP Archive.</p>
<p>The HTTP Archive analyzes the world’s top ~50K web pages on the 1st and 15th of the month and records the HTTP headers for every resource. Using this history it’s possible to go back in time and quantify how many of today’s resources without any max-age value were identical in previous crawls. The data for the chart above (showing 55% of resources with no max-age) was gathered on Feb 15 2012. The chart below shows the percentage of those uncacheable resources that were identical in the previous crawl on Feb 1 2012. We can go back even further and see how many were identical in both the Feb 1 2012 <em>and</em> the Jan 15 2012 crawls. (The HTTP Archive doesn’t save response bodies so the determination of “identical” is based on the resource having the exact same URL, Last-Modified, ETag, and Content-Length.)</p>
<p><img class="aligncenter" title="Uncacheable resources used in previous crawls" src="http://stevesouders.com/images/ha-uncacheable-reused-20120215.png" alt="" width="480" height="310" /></p>
<p><strong>46% of the resources without any max-age remained unchanged over a 2 week period</strong>. This works out to 21 resources per page that <em>could</em> have been read from cache without any HTTP request but <em>weren’t</em>. Over a 1 month period 38% are unchanged – 17 resources per page.</p>
<p>This is a significant missed opportunity. Here are some popular websites and the number of resources that were unchanged for 1 month but did not specify max-age:</p>
<ul>
  <li><a href="http://httparchive.org/viewsite.php?pageid=910249">http://www.toyota.jp/</a> – 172 resources without max-age &amp; unchanged for 1 month</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=903881">http://www.sfgate.com/</a> – 133</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=909871">http://www.hasbro.com/</a> – 122</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=904089">http://www.rakuten.co.jp/</a> – 113</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=906489">http://www.ieee.org/</a> – 97</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=904247">http://www.elmundo.es/</a> – 80</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=904221">http://www.nih.gov/</a> – 76</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=906605">http://www.frys.com/</a> – 68</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=904541">http://www.foodnetwork.com/</a> – 66</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=903471">http://www.irs.gov/</a> – 58</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=904517">http://www.ca.gov/</a> – 53</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=903513">http://www.oracle.com/</a> – 52</li>
  <li><a href="http://httparchive.org/viewsite.php?pageid=904341">http://www.blackberry.com/</a> – 50</li>
</ul>
<p>Recalling that “the fastest HTTP request is the one not made”, this is a lot of unnecessary HTTP traffic. I can’t prove it, but I strongly believe this is not intentional – it’s just a lack of awareness. The chart below reinforces this belief – it shows the percentage of resources (both cacheable and uncacheable) that remain unchanged starting from Feb 15 2012 and going back for one year.</p>
<p><a href="http://stevesouders.com/images/ha-reused-20120215-full.png"><img class="aligncenter" title="Resources unchanged over time" src="http://stevesouders.com/images/ha-reused-20120215.png" alt="" width="480" height="273" /></a></p>
<p>The percentage of resources that are unchanged is nearly the same when looking at all resources as it is for only uncacheable resources: 44% vs. 46% going back 2 weeks and 35% vs. 38% going back 1 month. Given this similarity in “dynamicness” it’s likely that the absence of max-age has nothing to do with the resources themselves and is instead caused by website owners overlooking this best practice.</p>
<h3>3rd party content</h3>
<p>If a website owner doesn’t make their resources cacheable, they’re just hurting themselves (and their users). But if a 3rd party content provider doesn’t have good caching behavior it impacts all the websites that embed that content. This is both bad a good. It’s bad in that one uncacheable 3rd party resource can impact multiple sites. The good part is that shifting 3rd party content to adopt good caching practices also has a magnified effect.</p>
<p>So how are we doing when it comes to caching 3rd party content? Below is a list of the top 30 most-used resources according to the HTTP Archive. These are the resources that were used the most across the world’s top 50K web pages. The max-age value (in hours) is also shown.</p>
<ol>
  <li><a href="http://www.google-analytics.com/ga.js" target="_blank">http://www.google-analytics.com/ga.js</a> (2 hours)</li>
  <li><a href="http://ssl.gstatic.com/s2/oz/images/stars/po/Publisher/sprite2.png" target="_blank">http://ssl.gstatic.com/s2/oz/images/stars/po/Publisher/sprite2.png</a> (8760 hours)</li>
  <li><a href="http://pagead2.googlesyndication.com/pagead/js/r20120208/r20110914/show_ads_impl.js" target="_blank">http://pagead2.googlesyndication.com/pagead/js/r20120208/r20110914/show_ads_impl.js</a> (336 hours)</li>
  <li><a href="http://pagead2.googlesyndication.com/pagead/render_ads.js" target="_blank">http://pagead2.googlesyndication.com/pagead/render_ads.js</a> (336 hours)</li>
  <li><a href="http://pagead2.googlesyndication.com/pagead/show_ads.js" target="_blank">http://pagead2.googlesyndication.com/pagead/show_ads.js</a> (1 hour)</li>
  <li><a href="https://apis.google.com/_/apps-static/_/js/gapi/gcm_ppb,googleapis_client,plusone/rt=j/ver=DD_ff52ufs8.en_US./sv=1/am=!RERB5bJyvtSIVCfJNg/d=1/cb=gapi.loaded0" target="_blank">https://apis.google.com/_/apps-static/_/js/gapi/gcm_ppb,googleapis_client,plusone/[...]</a> (720 hours)</li>
  <li><a href="http://pagead2.googlesyndication.com/pagead/osd.js" target="_blank">http://pagead2.googlesyndication.com/pagead/osd.js</a> (24 hours)</li>
  <li><a href="http://pagead2.googlesyndication.com/pagead/expansion_embed.js" target="_blank">http://pagead2.googlesyndication.com/pagead/expansion_embed.js</a> (24 hours)</li>
  <li><a href="https://apis.google.com/js/plusone.js" target="_blank">https://apis.google.com/js/plusone.js</a> (1 hour)</li>
  <li><a href="http://googleads.g.doubleclick.net/pagead/drt/s?safe=on" target="_blank">http://googleads.g.doubleclick.net/pagead/drt/s?safe=on</a> (1 hour)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/y7/r/ql9vukDCc4R.png" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/y7/r/ql9vukDCc4R.png</a> (3825 hours)</li>
  <li><a href="http://connect.facebook.net/rsrc.php/v1/yQ/r/f3KaqM7xIBg.swf" target="_blank">http://connect.facebook.net/rsrc.php/v1/yQ/r/f3KaqM7xIBg.swf</a> (164 hours)</li>
  <li><a href="https://ssl.gstatic.com/s2/oz/images/stars/po/Publisher/sprite2.png" target="_blank">https://ssl.gstatic.com/s2/oz/images/stars/po/Publisher/sprite2.png</a> (8760 hours)</li>
  <li><a href="https://apis.google.com/_/apps-static/_/js/gapi/googleapis_client,iframes_styles_bubble_internal/rt=j/ver=DD_ff52ufs8.en_US./sv=1/am=!RERB5bJyvtSIVCfJNg/d=1/" target="_blank">https://apis.google.com/_/apps-static/_/js/gapi/googleapis_client,iframes_styles[...]</a> (720 hours)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/yv/r/ZSM9MGjuEiO.js" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/yv/r/ZSM9MGjuEiO.js</a> (8742 hours)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/yx/r/qP7Pvs6bhpP.js" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/yx/r/qP7Pvs6bhpP.js</a> (8699 hours)</li>
  <li><a href="https://plusone.google.com/_/apps-static/_/ss/plusone/ver=-1iqnlu1g4oiv4/am=!HKdu3RfMlih5oERU/bf=MQ/r=O" target="_blank">https://plusone.google.com/_/apps-static/_/ss/plusone/[...]</a> (720 hours)</li>
  <li><a href="http://b.scorecardresearch.com/beacon.js" target="_blank">http://b.scorecardresearch.com/beacon.js</a> (336 hours)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/yx/r/lP_Rtwh3P-S.css" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/yx/r/lP_Rtwh3P-S.css</a> (8710 hours)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/yA/r/TSn6F7aukNQ.js" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/yA/r/TSn6F7aukNQ.js</a> (8760 hours)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/yk/r/Wm4bpxemaRU.js" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/yk/r/Wm4bpxemaRU.js</a> (8702 hours)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/yZ/r/TtnIy6IhDUq.js" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/yZ/r/TtnIy6IhDUq.js</a> (8699 hours)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/yy/r/0wf7ewMoKC2.css" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/yy/r/0wf7ewMoKC2.css</a> (8699 hours)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/yO/r/H0ip1JFN_jB.js" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/yO/r/H0ip1JFN_jB.js</a> (8760 hours)</li>
  <li><a href="http://platform.twitter.com/widgets/hub.1329256447.html" target="_blank">http://platform.twitter.com/widgets/hub.1329256447.html</a> (87659 hours)</li>
  <li><a href="http://static.ak.fbcdn.net/rsrc.php/v1/yv/r/T9SYP2crSuG.png" target="_blank">http://static.ak.fbcdn.net/rsrc.php/v1/yv/r/T9SYP2crSuG.png</a> (8699 hours)</li>
  <li><a href="http://platform.twitter.com/widgets.js" target="_blank">http://platform.twitter.com/widgets.js</a> (1 hour)</li>
  <li><a href="https://plusone.google.com/_/apps-static/_/js/plusone/p1b,p1p/rt=j/ver=s9G1xxMtPkw.en_US./sv=1/am=!HKdu3RfMlih5oERU/d=1/" target="_blank">https://plusone.google.com/_/apps-static/_/js/plusone/[...]</a> (720 hours)</li>
  <li><a href="http://pagead2.googlesyndication.com/pagead/js/graphics.js" target="_blank">http://pagead2.googlesyndication.com/pagead/js/graphics.js</a> (24 hours)</li>
  <li><a href="http://s0.2mdn.net/879366/flashwrite_1_2.js" target="_blank">http://s0.2mdn.net/879366/flashwrite_1_2.js</a> (720 hours)</li>
</ol>
<p>There are some interesting patterns.</p>
<ul>
  <li><em>simple URLs have short cache times</em> – Some resources have very short cache times, e.g., ga.js (1), show_ads.js (5), and twitter.com/widgets.js (27). Most of the URLs for these resources are very simple (no querystring or URL “fingerprints”) because these resource URLs are part of the snippet that website owners paste into their page. These “bootstrap” resources are given short cache times because there’s no way for the resource URL to be changed if there’s an emergency fix – instead the cached resource has to expire in order for the emergency update to be retrieved.</li>
  <li><em>long URLs have long cache times</em> – Many 3rd party “bootstrap” scripts dynamically load other resources. These code-generated URLs are typically long and complicated because they contain some unique fingerprinting, e.g., http://pagead2.googlesyndication.com/pagead/js/<em>r20120208/r20110914</em>/show_ads_impl.js (3) and http://platform.twitter.com/widgets/hub.<em>1329256447</em>.html (25). If there’s an emergency change to one of these resources, the fingerprint in the bootstrap script can be modified so that a new URL is requested. Therefore, these fingerprinted resources can have long cache times because there’s no need to rev them in the case of an emergency fix.</li>
  <li><em>where’s Facebook’s like button?</em> – Facebook’s like.php and likebox.php are also hugely popular but aren’t in this list because the URL contains a querystring that differs across every website. Those resources have an even more aggressive expiration policy compared to other bootstrap resources – they use <code>no-cache, no-store, must-revalidate</code>. Once the like[box] bootstrap resource is loaded, it loads the other required resources: lP_Rtwh3P-S.css (19), TSn6F7aukNQ.js (20), etc. Those resources have long URLs and long cache times because they’re generated by code, as explained in the previous bullet.</li>
  <li><em>short caching resources are often async</em> – The fact that bootstrap scripts have short cache times is good for getting emergency updates, but is bad for performance because they generate many Conditional GET requests on subsequent requests. We all know that <a href="http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/">scripts block pages from loading</a>, so these Conditional GET requests can have a significant impact on the user experience. Luckily, some 3rd party content providers are aware of this and offer async snippets for loading these bootstrap scripts mitigating the impact of their short cache times. This is true for ga.js (1), plusone.js (9), twitter.com/widgets.js (27), and Facebook’s like[box].php.</li>
</ul>
<p>These extremely popular 3rd party snippets are in pretty good shape, but as we get out of the top widgets we quickly find that these good caching patterns degrade. In addition, more 3rd party providers need to support async snippets.</p>
<h3>Cache sizes are too small</h3>
<p>In January 2007 <a href="https://twitter.com/#%21/tenni08">Tenni Theurer</a> and I ran an <a href="http://www.yuiblog.com/blog/2007/01/04/performance-research-part-2/">experiment</a> at Yahoo! to estimate how many users had a primed cache. The methodology was to embed a transparent 1×1 image in the page with an expiration date in the past. If users had the expired image in their cache the browser would issue a Conditional GET request and receive a 304 response (primed cache). Otherwise they’d get a 200 response (empty cache). I was surprised to see that <strong>40-60% of daily users to the site didn’t have the site’s resources in their cache</strong> and 20% of page views were done without the site’s resources in the cache.</p>
<p><a href="http://www.yuiblog.com/blog/2007/01/04/performance-research-part-2/"><img class="aligncenter" title="Real user cache stats" src="http://yuiblog.com/assets/performance/cache-expt.gif" alt="" width="453" height="319" /></a></p>
<p>Numerous factors contribute to this high rate of unique users missing the site’s resources in their cache, but I believe the primary reason is small cache sizes. Browsers have increased the size of their caches since this experiment was run, but not enough. It’s hard to test browser cache size. Blaze.io’s article <a href="http://www.blaze.io/mobile/understanding-mobile-cache-sizes/">Understanding Mobile Cache Sizes</a> shows results from their testing. Here are the max cache sizes I found for browsers on my MacBook Air. (Some browsers set the cache size based on available disk space, so let me mention that my drive is 250 GB and has 54 GB available.) I did some testing and searching to find max cache sizes for my mobile devices and IE.</p>
<ul>
  <li>Chrome: <a href="http://code.google.com/p/chromium/issues/detail?id=16705">320</a> <a href="https://plus.google.com/103382935642834907366/posts/XRekvZgdnBb">MB</a></li>
  <li>Internet Explorer 9: <a href="http://blogs.msdn.com/b/ie/archive/2011/03/17/internet-explorer-9-network-performance-improvements.aspx">250 MB</a></li>
  <li>Firefox 11: 830 MB (shown in about:cache)</li>
  <li>Opera 11: 20 MB (shown in Preferences | Advanced | History)</li>
  <li>iPhone 4, iOS 5.1: 30-35 MB (based on testing)</li>
  <li>Galaxy Nexus: 18 MB (based on testing)</li>
</ul>
<p>I’m surprised that Firefox 11 has such a large cache size – that’s almost close to what I want. All the others are (way) too small. 18-35 MB on my mobile devices?! I have seven movies on my iPhone – I’d gladly trade <a href="http://itunes.apple.com/us/movie/iron-man-2/id390320341">Iron Man 2</a>  (1.82 GB) for more cache space.</p>
<h3>Caching in the real world</h3>
<p>In order to justify increasing browser cache sizes we need some statistics on how many real users overflow their cache. This topic came up at last month’s Velocity Summit where we had representatives from Chrome, Internet Explorer, Firefox, Opera, and Silk. (Safari was invited but didn’t show up.) <a href="https://plus.google.com/103382935642834907366/posts">Will Chan</a> from the Chrome team (working on SPDY) followed-up with this post on <a href="https://plus.google.com/103382935642834907366/posts/XRekvZgdnBb">Chromium cache metrics</a> from Windows Chrome. These are the most informative real user cache statistics I’ve ever seen. I strongly encourage you to read his article.</p>
<p>Some of the takeaways include:</p>
<ul>
  <li><strong>~30% of users have a full cache</strong> (capped at 320 MB)<strong><br />
  </strong></li>
  <li><strong>for users with a full cache, the median time to fill their cache is 4 hours of active browsing</strong> (20 hours of clock time)</li>
  <li>7% of users clear their cache at least once per week</li>
  <li>19% of users experience “fatal cache corruption” at least once per week thus clearing their cache</li>
</ul>
<p>The last stat about cache corruption is interesting – I appreciate the honesty. The IE 9 team experienced <a href="http://blogs.msdn.com/b/ie/archive/2011/03/17/internet-explorer-9-network-performance-improvements.aspx">something similar</a>. In IE 7&amp;8 the cache was capped at 50 MB based on tests showing increasing the cache size didn’t improve the cache hit rate. They revisited this surprising result in IE9 and found that larger cache sizes actually <em>did</em> improve the cache hit rate:</p>
<blockquote>
  <p>In IE9, we took a much closer look at our cache behaviors to better understand our surprising finding that larger caches were rarely improving our hit rate. We found a number of functional problems related to what IE treats as cacheable and how the cache cleanup algorithm works. After fixing these issues, we found larger cache sizes were again resulting in better hit rates, and as a result, we’ve changed our default cache size algorithm to provide a larger default cache.</p>
</blockquote>
<p>Will mentions that Chrome’s 320 MB cap should be revisited. 30% seems like a low percentage for full caches, but could be accounted for by users that aren’t very active and active users that only visit a small number of websites (for example, just Gmail and Facebook). If possible I’d like to see these full cache statistics correlated with activity. It’s likely that user who account for the biggest percentage of web visits are more likely to have a full cache, and thus experience slower page load times.</p>
<h3>Next steps</h3>
<p>First, much of the data for this post came from the <a href="http://httparchive.org/">HTTP Archive</a>, so I’d like to thank our <a href="http://httparchive.org/about.php#sponsors">sponsors</a>: <a title="Google" href="http://www.google.com/">Google</a>, <a title="Mozilla" href="http://www.mozilla.org/firefox">Mozilla</a>, <a title="New Relic" href="http://www.newrelic.com/">New Relic</a>, <a title="O'Reilly Media" href="http://oreilly.com/">O’Reilly Media</a>, <a href="http://www.etsy.com/">Etsy</a>, <a title="Strangeloop Networks" href="http://www.strangeloopnetworks.com/">Strangeloop</a>, <a title="dynaTrace Software" href="http://www.dynatrace.com/">dynaTrace Software</a>, and <a title="Torbit" href="http://torbit.com/">Torbit</a>.</p>
<p>The data presented here suggest a few areas to focus on:<em></em></p>
<p><strong>Website owners</strong> need to increase their use of a Cache-Control max-age, and the max-age times need to be longer. 38% of resources were unchanged over a 1 month period, and yet only 11% of resources have a max-age value that high. Most resources, even if they change, can be refreshed by including a fingerprint in the URL specified in the HTML document. Only bootstrap scripts from 3rd parties should have short cache times (hours). Truly dynamic responses (JSON, etc.) should specify must-revalidate. A year from now rather than seeing 55% of resources without any max-age value we should see 55% cacheable for a month or more.</p>
<p><strong>3rd party content providers</strong> need wider adoption of the caching and async behavior shown by the top Google, Twitter, and Facebook snippets.</p>
<p><strong>Browser developers</strong> stand to bring the biggest improvements to caching. Increasing cache sizes is a likely win, especially for mobile devices. Data correlating cache sizes and user activity is needed. More intelligence around purging algorithms, such as <a href="http://blogs.msdn.com/b/ie/archive/2011/03/17/internet-explorer-9-network-performance-improvements.aspx">IE 9′s prioritization based on mime type</a>, will help when the cache fills up. More focus on personalization (what are the sites I visit most often?) would also create a faster user experience when users go to their favorite websites.</p>
<p>It’s great that the number of resources with caching headers grew 10% over the last year, but that just isn’t enough progress. We should really expect to double the number of resources that can be read from cache over the coming year. Just think about all those HTTP requests that can be avoided!</p>
<p> </p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Fri, 23 Mar 2012 05:41:38 UT</pubDate>
            <guid>/entry/11/1187</guid>
        </item>
        <item>
            <title>@ThreeUK i've just received a firmware update for my Galaxy S2, is this ICS?</title>
            <link>http://adamleach.co.uk/entry/threeuk-ive-just-received-a-firmware-update-for-my-galaxy-s2-is-this-ics-14-386.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">@<a href="http://twitter.com/ThreeUK" target="_blank">ThreeUK</a> i've just received a firmware update for my Galaxy S2, is this ICS?</div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Tue, 20 Mar 2012 14:49:42 UT</pubDate>
            <guid>/entry/14/386</guid>
        </item>
        <item>
            <title>Added to a feed: A Thousand Platforms ...</title>
            <link>http://adamleach.co.uk/entry/a-thousand-platforms--11-1188.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1188">
<p>Today’s <a href="http://aws.amazon.com/elasticbeanstalk">AWS Elastic Beanstalk</a> <a href="http://aws.amazon.com/about-aws/whats-new/2012/03/20/php-and-git-deployment-for-aws-elastic-beanstalk/">announcement of PHP and Git support</a> reminded me of the <a href="http://www.allthingsdistributed.com/2011/01/aws_elastic_beanstalk.html">post</a> where I mentioned that we want to let a thousand platforms bloom on AWS. Some might ask why AWS would want a thousand platforms.</p>
<p>One of the most important AWS principles is <em>flexibility</em>. Flexibility is in the choice of software and languages running on AWS, in the tools and interfaces available to manipulate resources and applications, and in the ability to leverage services from other providers. One of our customers I met last week was talking about his application and how it runs on AWS; He collects geo-location data, analyzes and crunches this data using Elastic Map Reduce, stores the data for quick access in DynamoDB, runs his user interface on Heroku and his web services layer for mobile devices on Elastic Beanstalk. This application is a great way to highlight how developers might leverage different services, abstractions, and tools to deliver the most value to their customers.</p>
<p>If you’re seeking ultimate flexibility, AWS allows you to interact with services such as Amazon Elastic Compute Cloud (<a href="http://aws.amazon.com/ec2">Amazon EC2</a>) and Amazon Simple Storage Service (<a href="http://aws.amazon.com/S3">Amazon S3</a>) directly and to piece these services together in a building block fashion. This might incur some initial groundwork, especially if you just want to deploy a simple application. <a href="http://aws.amazon.com/cloudformation">AWS CloudFormation</a> can help bring the building blocks together through its template mechanism. This simplifies the provisioning and updates, but you’re still responsible for the operational aspects of running your application.</p>
<p>If you don’t need control over the software stack, you can use development platforms such as <a href="http://www.appfog.com">AppFog</a>, <a href="http://www.engineyard.com">Engine Yard</a>, and <a href="http://www.heroku.com">Heroku</a> to help you manage, deploy, and monitor your applications on AWS more easily. We’ve seen some newcomers in this space over the last year such as <a href="http://www.activestate.com/press-releases/activestate-brings-stackato-amazon-ec2">Stackato</a> and <a href="http://www.nodejitsu.com/">NodeJitsu</a>, and each platform continues to add value through highly curated software stacks and a set of management automation.</p>
<p><a href="http://aws.amazon.com/elasticbeanstalk">AWS Elastic Beanstalk</a> is another abstraction on top of the core AWS building blocks. It takes a different approach than most other development platforms by exposing the underlying resources. This approach provides the simplicity to quickly get started for application developers, but it also allows them to modify the stack to meet their goals. For example, one customer needed extensive Apache rewrite rules and a few other mods to meet his security requirements. He simply created a new AMI to use as his base for his Elastic Beanstalk container. Another pattern I have seen is customers attaching a debugger to the JVM running in their EC2 instance so that they can debug particular interaction patterns between their code and the JVM.</p>
<p>So is there a “one-size-fits-all” in the development platform space? No, each platform fits the needs of different developers, applications, and use cases. Preference and familiarity also play a role in why some developers choose one over the other. Ultimately, we want developers to successfully run and manage reliable, highly scalable applications on AWS, irrespective of the abstraction that their development platform of choice offers.</p>
<p>We will continue to work closely together with all current and future platform partners. Based on their feedback, we will develop new features and services that can help them be more successful by allowing them to focus on their customers instead of the infrastructure on which they run. This will also make it easier for new platforms to be developed such that developers will have more choice and flexibility, and they can really find the exact tools that make them most productive. AWS Elastic Beanstalk can play an important role there, too, because it is a good base for building new platforms. We are looking forward to seeing a thousand platforms bloom.</p>
<p>AWS Elastic Beanstalk now supports PHP applications (in addition to Java) and the ability to deploy through the popular <a href="http://git-scm.com/">Git version control system</a>. To get started using PHP and Git on AWS Elastic Beanstalk, visit <a href="http://docs.amazonwebservices.com/elasticbeanstalk/latest/dg/create_deploy_PHP.html">Deploying PHP Applications Using Git</a> in the AWS Elastic Beanstalk Developer Guide. More details about the release at the <a href="http://aws.typepad.com/aws/2012/03/aws-elastic-beanstalk-build-php-apps-using-git-based-deployment.html">AWS developer blog</a>.</p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 20 Mar 2012 04:00:00 UT</pubDate>
            <guid>/entry/11/1188</guid>
        </item>
        <item>
            <title>My Top 3 #lastfm Artists: deadmau5 (18), Knife Party (8) &amp;amp;amp; ZEDD (4) #music http://t. ...</title>
            <link>http://adamleach.co.uk/entry/my-top-3-lastfm-artists-deadmau5-18-knife-party-8-amp-zedd-4-mu-14-385.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">My Top 3 #lastfm Artists: deadmau5 (18), Knife Party (8) &amp;amp; ZEDD (4) #music <a href="http://t.co/9PBYJUMP" target="_blank">http://t.co/9PBYJUMP</a></div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Mon, 19 Mar 2012 07:37:21 UT</pubDate>
            <guid>/entry/14/385</guid>
        </item>
        <item>
            <title>Added to a feed: A list of ZF2 events</title>
            <link>http://adamleach.co.uk/entry/a-list-of-zf2-events-11-1189.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1189">
<p>Both the Module Manager and the MVC system use the Event Manger extensively in order to provide "hook points" for you to add your own code into the application flow. This is a list of the events triggered by each class during a standard request with the Skeleton Application:</p>
<h4>Module Manager</h4>
<ul>
  <li>ZendModuleManager: <em>loadModules.pre</em></li>
  <li>For every module: 
  <ul>
    <li>ZendModuleManager: <em>loadModule.resolve</em></li>
    <li>ZendModuleManager: <em>loadModule</em></li>
  </ul>
  </li>
  <li>ZendModuleManager: <em>loadModules.post</em></li>
</ul>
<h4>Bootstrap</h4>
<ul>
  <li>ZendMvcBootstrap: <em>bootstrap</em></li>
</ul>
<h4>Application</h4>
<p>Successful:</p>
<ul>
  <li>ZendMvcApplication: <em>route</em></li>
  <li>ZendMvcApplication: <em>dispatch</em> 
  <ul>
    <li>ZendMvcControllerActionController: <em>dispatch</em> (if controller extends this class)</li>
  </ul>
  </li>
  <li>ZendMvcApplication: <em>render</em></li>
  <li>ZendViewView: <em>renderer</em></li>
  <li>ZendViewView: <em>response</em></li>
  <li>ZendMvcApplication: <em>finish</em></li>
</ul>
<ul>
  <li>ZendMvcApplication: <em>dispatch.error</em></li>
  <li>ZendMvcApplication: <em>render</em></li>
  <li>ZendViewView: <em>renderer</em></li>
  <li>ZendViewView: <em>response</em></li>
  <li>ZendMvcApplication: <em>finish</em></li>
</ul>
<p>Note that routing and dispatching is also implemented using these registered events, so you can implement "pre" and "post" hooks by changing the priority of the listener that you register.</p>
<p><a href="http://akrabat.com/?flattrss_redirect&amp;id=1902&amp;md5=0b1c982f225be227c39d26de8b63fd8e" title="Flattr" target="_blank"><img src="http://akrabat.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Fri, 16 Mar 2012 08:56:12 UT</pubDate>
            <guid>/entry/11/1189</guid>
        </item>
        <item>
            <title>Added to a feed: Ralph Schindler: PHP Constructor Best Practices And The Prototype Pattern</title>
            <link>http://adamleach.co.uk/entry/ralph-schindler-php-constructor-best-practices-and-the-prototype-pattern-11-1190.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1190">
<p>Ralph Schindler has posted <a href="http://ralphschindler.com/2012/03/09/php-constructor-best-practices-and-the-prototype-pattern">PHP Constructor Best Practices And The Prototype Pattern</a></p>
<blockquote>
  <p>If your knowledge of constructors ends with &ldquo;the place where I put my object initialization code,&rdquo; read on. While this is mostly what a constructor is, the way a developer crafts their class constructor greatly impacts the initial API of a particular class/object; which ultimately affects usability and extensibility. After all, the constructor is the first impression a particular class can make.</p>
</blockquote>
<p>In case you missed this last Friday, this is an in-depth look at how to construct an object in PHP whilst adhering to SOLID principles. If you missed this last week, read it now! Get a coffee first.</p>
<p><a href="http://akrabat.com/?flattrss_redirect&amp;id=1911&amp;md5=8579bbd1bbefff14f29492bc70fcf99a" title="Flattr" target="_blank"><img src="http://akrabat.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Thu, 15 Mar 2012 10:49:58 UT</pubDate>
            <guid>/entry/11/1190</guid>
        </item>
        <item>
            <title>Added to a feed: Tiernan’s Podcast, Episode 1</title>
            <link>http://adamleach.co.uk/entry/tiernanys-podcast-episode-1-11-1191.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1191">So, my new podcast is now live! I am a podcaster again! for the next 3 weeks (Today, Tuesday 20th and Tuesday 27th) a new episode will auto publish. If you want to get them on your iPod, iPhone, i(Insert &#8230;
<p class="read-more"><a href="http://blog.lotas-smartman.net/tiernans-podcast-episode-1">Read more &#187;</a></p>
<p><a href="http://feedads.g.doubleclick.net/~a/HythXpmN-gR4_xuhM7W461PvdDk/0/da"><img src="http://feedads.g.doubleclick.net/~a/HythXpmN-gR4_xuhM7W461PvdDk/0/di" ismap="ismap" alt="image" style="border: 0px;" /></a><br />
<a href="http://feedads.g.doubleclick.net/~a/HythXpmN-gR4_xuhM7W461PvdDk/1/da"><img src="http://feedads.g.doubleclick.net/~a/HythXpmN-gR4_xuhM7W461PvdDk/1/di" ismap="ismap" alt="image" style="border: 0px;" /></a></p>
<div class="feedflare">
  <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/lotas?d=yIl2AUoC8zA" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/lotas?d=dnMXMwOfBR0" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/lotas?d=7Q72WNTAKBA" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/lotas?i=FvyzbhJlq50:iZfNOAmaYSo:D7DqB2pKExk" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:JEwB19i1-c4"><img src="http://feeds.feedburner.com/~ff/lotas?i=FvyzbhJlq50:iZfNOAmaYSo:JEwB19i1-c4" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:ozPqQDaSF7U"><img src="http://feeds.feedburner.com/~ff/lotas?i=FvyzbhJlq50:iZfNOAmaYSo:ozPqQDaSF7U" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:XQ266DUsA9M"><img src="http://feeds.feedburner.com/~ff/lotas?d=XQ266DUsA9M" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:ANkz6nJbUoM"><img src="http://feeds.feedburner.com/~ff/lotas?d=ANkz6nJbUoM" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/lotas?d=qj6IDK7rITs" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/lotas?i=FvyzbhJlq50:iZfNOAmaYSo:V_sGLiPBpWU" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/lotas?d=YwkR-u9nhCs" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/lotas?a=FvyzbhJlq50:iZfNOAmaYSo:wd9GD17jvC4"><img src="http://feeds.feedburner.com/~ff/lotas?d=wd9GD17jvC4" alt="image" style="border: 0px;" /></a>
</div>
<img src="http://feeds.feedburner.com/~r/lotas/~4/FvyzbhJlq50" height="1" width="1" alt="image" /></div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 13 Mar 2012 21:46:13 UT</pubDate>
            <guid>/entry/11/1191</guid>
        </item>
        <item>
            <title>Added to a feed: Slides: MySQL 5.6 Global Transaction Identifier and PECL/mysqlnd_ms for failover</title>
            <link>http://adamleach.co.uk/entry/slides-mysql-56-global-transaction-identifier-and-peclmysqlndms-for-fai-11-1192.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1192">
<p style="text-align: center;"></p>
<div style="width:425px">
  <strong style="display:center;margin:12px 0 4px"><a href="http://www.slideshare.net/nixnutz/mysql-56-global-transaction-identifier-use-case-failover" title="MySQL 5.6 Global Transaction Identifier - Use case: Failover" target="_blank">MySQL 5.6 Global Transaction Identifier - Use case: Failover</a></strong> <br />
  <div style="padding:5px 0 12px">
    View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> on <a href="http://www.slideshare.net/nixnutz" target="_blank">PHP and MySQL</a>
  </div>
</div>
<p>The long lasting MySQL replication failover issue is cured. MySQL 5.6 makes master failover easy, <a href="http://de.php.net/mysqlnd_ms">PECL/mysqlnd_ms</a> assists with the client/connection failover. Compared to the past this is a significant step towards improving MySQL replication cluster availability, eleminating the need to use 3rd party tools in many cases. The slides illustrate the basic idea, <a href="http://blog.ulf-wendel.de/2011/wonders-of-global-transaction-id-injection/">as blogged about before</a>.</p>
<p>There is not much to say about the feature as such. Slave to master promotion works without hassles, finally. Regardless if you do failover because of an error of the current master or switchover because you want to change the master server, its easy now. Congratulations to the replication team!</p>
<h3>Limitations of the current server implementation</h3>
<p>The global transaction identifier implementation in MySQL 5.6 has a couple of limitations, though. Its not hard to guess that mixing transactional and non-transactional updates in one transaction can cause problems. Its pretty much the first pitfall I ran into when trying to setup a MySQL 5.6.5-m8 (not 5.6.4-m8&#8230;) slave using a <code>mysqldump</code> generated SQL dump. MySQL bailed at me and stopped me from failing.</p>
<p><a id="more-351"></a></p>
<p>Let a master run a transaction which first updates an InnoDB table. followed by an update of a MyISAM table, followed by another update: <code>t(U<sup>InnoDB</sup>, U<sup>MyISAM</sup>, U<sup>X</sup>)</code>. Let the binary log settings be so that this transaction is written as one to the binary log (<code>binlog_format=statement, binlog_direct_non_transactional_updates=0</code>). It is then copied &#8220;as is&#8221; to the relay log of a slave. Assume that the slave runs with different binary log settings so that <code>t(U<sup>InnoDB</sup>, U<sup>MyISAM</sup>, U<sup>X</sup>)</code> is split up to <code>t(U<sup>MyISAM</sup>), t(U<sup>InnoDB</sup>[, &#8230;])</code>and logged as distinct transactions in the slaves binary log.</p>
<table cellspacing="2" cellpadding="2">
  <tr style="background-color: #e0e0e0;">
    <th align="center" valign="top" colspan="4">Worst case: conflicting binary log settings</th>
    <th></th>
  </tr>
  <tr>
    <th align="center" valign="top" colspan="2" style="background-color: #f0f0f0;">Master</th>
    <th align="center" valign="top" colspan="2" style="background-color: #f0f0f0;">Slave</th>
  </tr>
  <tr>
    <td align="left" valign="top">GTID=M:1</td>
    <td align="left" valign="top"><code>t(U<sup>InnoDB</sup>, U<sup>MyISAM</sup>, U<sup>X</sup>)</code></td>
    <td align="left" valign="top">GTID=M:1</td>
    <td align="left" valign="top"><code>t(U<sup>MyISAM</sup>)</code></td>
  </tr>
  <tr>
    <td colspan="2"></td>
    <td align="left" valign="top" style="background-color: #fff0f0;">GTID=M:1</td>
    <td align="left" valign="top"><code>t(U<sup>InnoDB</sup>[, &#8230;])</code></td>
  </tr>
</table>
<p>Because slaves must preserve global transaction identifiers they got from their master, the two resulting transactions are given the same identifier. The transaction identifier in the slaves binary log is no longer unique, it now refers to two transactions not just one (issue #1). Any slave that would read from the binary log of the above slave may loose the InnoDB transaction because it may refuse to execute a transaction using an id that has been executed already (issue #2).</p>
<p>The workaround? Don&#8217;t mix InnoDB and MyISAM updates in one transaction. To me it does not sound that much of an issue in 2012. Please note, I&#8217;m describing my experience with MySQL 5.6.5-m8, which is a development version.</p>
<h3>The load balancer update</h3>
<p>MySQL Replication takes a primary copy approach to replication. A primary/master handles all the updates. Read-only replicas/slaves replicate from the primary. The primary is a single point of failure.</p>
<table cellspacing="2" cellpadding="2" width="100%">
  <tr>
    <td align="left" valign="top" style="background-color: #f0f0f0;">Writes</td>
    <td align="center" colspan="3" style="background-color: #f0fff0;">Primary/master</td>
  </tr>
  <tr>
    <td align="left" valign="top" style="background-color: #f0f0f0;">Reads</td>
    <td align="center" valign="top" style="background-color: #f0fff0;">Slave</td>
    <td align="center" valign="top">&nbsp;</td>
    <td align="center" valign="top" style="background-color: #f0fff0;">Slave</td>
  </tr>
</table>
<p>The failure of a slave is unproblematic. A client usually has plenty of other slaves to start reading from. If no slave is available, reads can even be forwarded to the master.</p>
<table cellspacing="2" cellpadding="2" width="100%">
  <tr>
    <td align="center" valign="top" colspan="3" style="background-color: #f0f0f0;">PHP</td>
  </tr>
  <tr>
    <td align="center" valign="top" colspan="3" style="background-color: #e0e0e0;">Load Balancer, e.g PECL/mysqlnd_ms</td>
    <td></td>
  </tr>
  <tr>
    <td align="center" valign="top" colspan="3">Read</td>
  </tr>
  <tr>
    <td align="center" valign="top" style="background-color: #fff0f0;"><del>Slave</del></td>
    <td align="center" valign="top">&nbsp;</td>
    <td align="center" valign="top" style="background-color: #f0fff0;">Slave</td>
  </tr>
</table>
<p>All a PECL/mysqlnd_ms user has to do is check for an error after statement execution. If there&#8217;s one and the error code hints that the server has gone away, the user reruns the statement. The connection handle remains useable all the time. Upon rerun, PECL/mysqlnd_ms openes a new connection to another slave.</p>
<p><code></code></p>
<pre>
do {
  $res = $mysql-&gt;query(&quot;SELECT id, title FROM news&quot;);
} while (isset($connection_error_codes[$mysql-&gt;errno]));
	
if (!$res) {
  bail(&quot;SQL error&quot;, $mysql-&gt;errno, $mysql-&gt;error);
}
</pre>
<p></p>
<p>A master failure is much more problematic. There is no server to send a write to but the master. The master is a single point of failure. The new global transaction identifier help to reduce the time it takes to put a new master in place after a failure.</p>
<table cellspacing="2" cellpadding="2" width="100%">
  <tr>
    <td align="center" valign="top" colspan="3" style="background-color: #f0f0f0;">PHP</td>
  </tr>
  <tr>
    <td align="center" valign="top" colspan="3" style="background-color: #e0e0e0;">Load Balancer, e.g PECL/mysqlnd_ms</td>
    <td></td>
  </tr>
  <tr>
    <td align="center" valign="top" colspan="3">Write</td>
  </tr>
  <tr>
    <td align="center" valign="top" colspan="3" style="background-color: #fff0f0;"><del>Master</del></td>
  </tr>
</table>
<p>After a master failure some process needs to promote a former slave to the new master and, preferrable atomically, update all other slaves to start replicating from the new master. The below illustration is a bit confusing. It is intentionally. What happens during the simple to say &#8220;slave to master promotion&#8221; is a complete restructuring of the cluster.</p>
<table cellspacing="2" cellpadding="2" width="100%">
  <tr>
    <td align="left" valign="top" style="background-color: #f0f0f0;"><del>Writes</del></td>
    <td align="left" valign="top" style="background-color: #e0e0e0;">&nbsp;</td>
    <td align="center" colspan="3" style="background-color: #fff0f0;"><del>Primary/master</del> (gone)</td>
  </tr>
  <tr>
    <td align="left" valign="top" style="background-color: #f0f0f0;"><del>Read</del></td>
    <td align="left" valign="top" style="background-color: #e0e0e0;">Write</td>
    <td align="center" valign="top" style="background-color: #f0fff0;"><del>Slave</del> Master (promoted former slave)</td>
  </tr>
  <tr>
    <td align="left" valign="top" style="background-color: #f0f0f0;"><del>Read</del></td>
    <td align="left" valign="top" style="background-color: #e0e0e0;">Read</td>
    <td align="center" valign="top" style="background-color: #f0fff0;">Slave (no change)</td>
  </tr>
</table>
<h3>Don&#8217;t forget to update the load balancer</h3>
<p>After the cluster has been reorganized, the load balancer configurations must be updated. PECL/mysqlnd_ms happens to be a driver integrated load balancer. However, other than that, it is not different from a classical load balancer. Whatever process restructures the cluster it must take care of deploying the load balancer configurations afterwards.</p>
<p>Global transaction identifiers are a great help for the biggest part of the failover job - the server side. But, they are no swiss army knife. Don&#8217;t forget to update your load balancer configuration - the client side. No matter where it is. Whether it is part of the application code, driver integrated or you are using MySQL Proxy. As long as we are talking primary copy, a master failure will always be a major pain.</p>
<p>Happy hacking!</p>
<p style="text-align: center;"><a href="http://twitter.com/#!/Ulf_Wendel">@Ulf_Wendel&nbsp;<img src="http://blog.ulf-wendel.de/images/twitter.png" alt="Follow me on Twitter" style="text-align: middle;" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 13 Mar 2012 13:00:23 UT</pubDate>
            <guid>/entry/11/1192</guid>
        </item>
        <item>
            <title>Added to a feed: Pádraic Brady: A Hitchhiker’s Guide to Cross-Site Scripting (XSS) in PHP ...</title>
            <link>http://adamleach.co.uk/entry/pydraic-brady-a-hitchhikerys-guide-to-cross-site-scripting-xss-in-php-11-1193.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1193">
<p>Pádraic Brady has posted <a href="http://blog.astrumfutura.com/2012/03/a-hitchhikers-guide-to-cross-site-scripting-xss-in-php-part-1-how-not-to-use-htmlspecialchars-for-output-escaping/">A Hitchhiker&rsquo;s Guide to Cross-Site Scripting (XSS) in PHP (Part 1): How Not To Use Htmlspecialchars() For Output Escaping</a>:</p>
<blockquote>
  <p>Always set the third parameter to htmlspecialchars(), set it correctly, and make sure your document is never served with a mismatched or invalid character encoding! Don&rsquo;t expect some theoretically perfect world to magically appear - browsers are filthily efficient at doing weird things you don&rsquo;t expect.</p>
</blockquote>
<p>With a nod to the anniversary of <a href="http://en.wikipedia.org/wiki/Douglas_Adams">Douglas Adams</a>' death on Sunday, Pádraic Brady has written possibly the definitive guide to the <tt>htmlspecialchars()</tt> function.</p>
<p>Read it. Then read it again.</p>
<p><a href="http://akrabat.com/?flattrss_redirect&amp;id=2116&amp;md5=3d190af2076fb776c48fd8a973da52d5" title="Flattr" target="_blank"><img src="http://akrabat.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Tue, 13 Mar 2012 11:27:41 UT</pubDate>
            <guid>/entry/11/1193</guid>
        </item>
        <item>
            <title>Added to a feed: A Hitchhiker’s Guide to Cross-Site Scripting (XSS) in PHP (Part 1): How Not ...</title>
            <link>http://adamleach.co.uk/entry/a-hitchhikerys-guide-to-cross-site-scripting-xss-in-php-part-1-how-n-11-1194.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1194">
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
  <a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2012%2F03%2Fa-hitchhikers-guide-to-cross-site-scripting-xss-in-php-part-1-how-not-to-use-htmlspecialchars-for-output-escaping%2F"><br />
  <img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2012%2F03%2Fa-hitchhikers-guide-to-cross-site-scripting-xss-in-php-part-1-how-not-to-use-htmlspecialchars-for-output-escaping%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=Character+encodings+in+HTML,Cross-Site+Scripting,php,xss&amp;b=2" height="61" width="50" alt="image" /><br />
  </a>
</div>
<div class="wp-caption alignright" style="width: 250px">
  <a href="http://www.flickr.com/photos/57704929@N00/3528646651" target="_blank"><img class="zemanta-img-inserted zemanta-img-configured" title="Nu wordt het wel heel simpel om XSS zwakheden ..." src="http://farm3.static.flickr.com/2194/3528646651_a16d9053e1_m.jpg" alt="Nu wordt het wel heel simpel om XSS zwakheden ..." width="240" height="139" /></a>
  <p class="wp-caption-text">(Photo credit: bertboerland)</p>
</div>
<p>In recent weeks, I consulted with the second most intelligent species on the planet: Dolphins. Dolphins are renowned across the known Universe for their awesome programming skills. After all, it was they who developed such insightful works as &#8220;Evolution By Example&#8221;, &#8220;Dude! We Wrote The Laws Of Physics!&#8221;, and &#8220;How Many Humans Does It Take To Screw Up A Planet?&#8221;. The answer to the last will be published on 01/01/2013 after the experiment is shut down and sent to a landfill site assuming the Supreme Spaghetti Monster signs off on the permit.</p>
<p>Dolphins think we are really dumb and theorise that this level of stupidity has one obvious cause: self-imposed ignorance. We are, after all, only the third most intelligent species on Earth and appear to have aspirations to lower our IQ just a bit more.</p>
<p>While it&#8217;s no harm poking fun at ourselves, in PHP we do have a serious problem. <a class="zem_slink" title="Cross-site scripting" rel="wikipedia" href="http://en.wikipedia.org/wiki/Cross-site_scripting" target="_blank">Cross-Site Scripting</a> (XSS) remains one of the most significant classes of security problems afflicting PHP applications. Despite years of education, community awareness and the development of frameworks which can offer a huge boost in consistent practices &#8211; things are not getting any better.</p>
<p>So, I finally figured out what the core problem is: PHP programmers are completely clueless about XSS. It&#8217;s that simple. Instead of going out and studying the topic, we blindly follow some preferred herd of people offering advice with heartfelt conviction despite the fact that they are probably just as ignorant as the rest of us. Does that sound like the behaviour of something which allegedly evolved into an intelligent species? The result is a mix of ignorance and stagnant knowledge that leaves PHP in an unenviable position beset by wrongheaded zealots.</p>
<p>To get the ball rolling, this two-part article series is a tour of how NOT to use <a href="http://ie2.php.net/manual/en/function.htmlspecialchars.php" target="_blank">the htmlspecialchars() function</a> that is typically pressed ganged into service as PHP&#8217;s universal output escaper. By offering an example based guide, I hope it will illustrate just how many ways a prospective attacker using XSS can exploit this function&#8217;s misuse to pull off a successful attack. The examples were written for PHP 5.3, so 5.4 users may need to imagine they still have 5.3 installed and/or lodge an official complaint with somebody who looks like they keep a complaints box handy (your local fast food restaurant is a good start).</p>
<p>This example led approach has another motive. Simple examples can be translated into unit tests. Ideally, many of the current crop of frameworks can use this article as a guide to what their unit tests should be looking for. This also makes it far easier for everyday programmers to consume the article and run around the place, drunk with ungodly power, identifying issues in the libraries, frameworks and other projects that they rely on.</p>
<p>To help us on the path of enlightenment before it&#8217;s too late (I&#8217;d lodge an appeal with the Supreme Spaghetti Monster but apparently the Mayans already tried and failed), I also invite other PHP programmers to blog about a security topic over the next month or two. Give programmers one last chance to get it right before the Planet is demolished by the Vogon destructor fleet. Just pick a topic that drives you up the walls in defiance of gravity and spend an hour writing something useful and (optionally) expletive filled. Every little bit helps.</p>
<h1>What Is Htmlspecialchars()?</h1>
<p>According to many programmers from Earth, htmlspecialchars() is a function used to escape output to prevent XSS. This is however a completely wrong definition. The function was actually co-opted by programmers to combat XSS because it was either that or create slow userland functions for which the internals developers might get around to creating, when the full moon coincided with the right planetary alignment in another 314 years, a speedier C alternative to. The actual definition (along with a half-hearted self-doubting nod to preventing XSS) is as follows:</p>
<blockquote>
  <p>Certain characters have special significance in HTML, and should be represented by HTML entities if they are to preserve their meanings. This function returns a string with some of these conversions made; the translations made are those most useful for everyday web programming. If you require all HTML character entities to be translated, use htmlentities() instead. This function is useful in preventing user-supplied text from containing HTML markup, such as in a message board or guest book application.</p>
</blockquote>
<p>Note that this hints at, but does not explicitly use, the terms Cross-Site Scripting, XSS or even Security. Then again, it does refer to guest book applications so it was probably written in 1790 by the Dolphin who created PHP v86 and who then got around to backporting version 1.0 for Humans in the late 20th Century out of extreme pity for our reliance on CGI. No, not the let&#8217;s take an action movie and turn it into a plotless eyesore with computer generated fake stuff style CGI &#8211; though memories of both are comparably bad.</p>
<p>Does this make htmlspecialchars() terrible at preventing XSS? No. As part of a comprehensive well-understood strategy to prevent XSS, the function is very useful. However, in PHP it is frequently overused, misused, abused, confused and&#8230;. Darn it, ran out of rhyming words again. Suffice it to say that a good description of htmlspecialchars() is that it&#8217;s an unsuitable tool for preventing XSS that has slowly evolved into a better suited tool over the years. I keep telling myself that, at least.</p>
<p>The function, htmlspecialchars(), accepts four parameters. Here is its function prototype as of PHP 5.4:</p>
<pre>string htmlspecialchars ( string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string $encoding = 'UTF-8' [, bool $double_encode = true ]]] )</pre>
<p>The first parameter accepts a string whose special HTML characters will be converted to HTML entities. The second accepts one or more flags which defaults to using ENT_COMPAT (does not convert single quotes to entities) but should be set to use ENT_QUOTES (does convert single quotes to entities). You can include another flag, in PHP 5.4, called ENT_SUBSTITUTE which is not a bad idea for UTF-8, i.e. ENT_QUOTES | ENT_SUBSTITUTE. You can pretend that all the other constants don&#8217;t exist. The third parameter accepts a string indicating the <a class="zem_slink" title="Character encoding" rel="wikipedia" href="http://en.wikipedia.org/wiki/Character_encoding" target="_blank">character encoding</a> of the string being processed and defaults to ISO-8859-1 for PHP 5.3, and UTF-8 for PHP 5.4. Don&#8217;t ever set the fourth parameter to TRUE when escaping unless your filtering logic was written by an Über Dolphin &#8211; always keep filtering and escaping separate from each other to avoid confusing the two and then having to pointlessly argue why your way is better in defiance of all logic.</p>
<p>The function, if correctly configured using this super simple article for guidance, will now convert the following characters to entities: &lt;, &gt;, &#8216;, &#8221; and &amp;. These characters make sense to escape since they are used to construct HTML tags, delineate attribute values or reference HTML entities &#8211; none of which we want users to be able to do!</p>
<p>If you want some very good advice before your brain implodes from too much reading, a good way to potentially make yourself vulnerable to XSS is to not explicitly set the first two optional parameters ($flags and $encoding) to an appropriate value. In fact, if you see htmlspecialchars() missing any of those two parameters in someone&#8217;s source code, you should request that they fix it or, at the very least, curse their name and pray for the Supreme Spaghetti Monster to label them as biohazardous waste in need of emergency disposal.</p>
<p>Now, let&#8217;s get down to overloading your brain with information. I&#8217;m told that this part is like being sucked into the <a class="zem_slink" title="Technology in The Hitchhiker's Guide to the Galaxy" rel="wikipedia" href="http://en.wikipedia.org/wiki/Technology_in_The_Hitchhiker%27s_Guide_to_the_Galaxy" target="_blank">Total Perspective Vortex</a> machine on Frogstar World B.</p>
<h1>To Quote Or Not To Quote. How Is That A Question?</h1>
<p>As it turns out, HTML is not simply a popular markup language, it is a popular markup language designed by a bureaucratic species of transdimensional beings seeking to drive Humanity insane by inventing the most impossible-to-secure markup language known in 172 Universes which is then interpreted by &#8220;browsers&#8221; written by Mice to test the patience of security professionals and keep the really intelligent Humans distracted from the truth of their soon-to-end existence as they search out ever more ludicrous examples of parsing weirdness. Excuse me, I held my breath writing that and need to fetch my Oxygen tank&#8230;</p>
<p>Consider the following example. If you want to see whether they work without copy pasting, you can clone all examples from my ominously titled <a href="https://github.com/padraic/xss" target="_blank">xss repository on Github</a> into a webroot somewhere to read or execute them.</p>
<div id="wpshdo_1" class="wp-synhighlighter-outer">
  <div id="wpshdt_1" class="wp-synhighlighter-expanded">
    <table border="0" width="100%">
      <tr>
        <td align="left" style="width: 80%;"><a name="#codesyntax_1"></a><a id="wpshat_1" class="wp-synhighlighter-title" href="http://blog.astrumfutura.com/#codesyntax_1" title="Click to show/hide code block">Single Quoted Attributes</a></td>
        <td align="right"><a href="http://blog.astrumfutura.com/#codesyntax_1" title="Show code only"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/#codesyntax_1" title="Print code"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Show plugin information"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" alt="image" /></a>&nbsp;</td>
      </tr>
    </table>
  </div>
  <div id="wpshdi_1" class="wp-synhighlighter-inner" style="display: block;">
    <div class="php" style="font-family:monospace;">
      <ol>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <a href="http://www.php.net/header"><span style="color: #990000;">header</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Content-Type: text/html; charset=UTF-8'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;!DOCTYPE html&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$input</span> <span style="color: #339933;">=</span> <span style="color: #0000cc; font-style: italic;">&lt;&lt;&lt;INPUT</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">' onmouseover='alert(/Meow!/);</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">INPUT</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">/**</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;* NOTE: This is equivalent to using htmlspecialchars($input, ENT_COMPAT)</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;*/</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$output</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/htmlspecialchars"><span style="color: #990000;">htmlspecialchars</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$input</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;html&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;head&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;title&gt;Single Quoted Attribute&lt;/title&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/head&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;body&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;div&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">        &lt;span title='<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$output</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>'&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">            What's that latin placeholder text again?</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">        &lt;/span&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;/div&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/body&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/html&gt;</pre>
        </li>
      </ol>
    </div>
  </div>
</div>
<p>If you run the example from a browser and pass your mouse pointer over the text, you will get a popup saying &#8220;/Meow!/&#8221;. Granted, this is hardly the most impressive XSS ever but remember that the Javascript executed could be a lot more ingenious and damaging. The reason you see alert() used everywhere in XSS examples is to prove that Javascript was executable &#8211; a real attacker will hardly advertise his success like this.</p>
<p>In this case, the htmlspecialchars() function call omits the second parameter which defaults to using the ENT_COMPAT flag. With this setting, the function does not convert single quotes to entities, allowing us to inject an unescaped single quote (to close the title attribute value) and another to start a new attribute and value which will be closed by the final single quote used in the template.</p>
<p>We can fix this problem in one of two ways:</p>
<p>1. Use double quotes which will prevent user input from breaking out of the HTML attribute value context using single quotes; or</p>
<p>2. Set the second parameter to htmlspecialchars() to use the ENT_QUOTES flag which will escape any single quotes a user tries to inject.</p>
<p>The moral of the story can be made even clearer by another example. In this case we use another perfectly validating means of delineating attribute values in HTML5 &#8211; we just don&#8217;t bother using quotes at all!</p>
<div id="wpshdo_2" class="wp-synhighlighter-outer">
  <div id="wpshdt_2" class="wp-synhighlighter-expanded">
    <table border="0" width="100%">
      <tr>
        <td align="left" style="width: 80%;"><a name="#codesyntax_2"></a><a id="wpshat_2" class="wp-synhighlighter-title" href="http://blog.astrumfutura.com/#codesyntax_2" title="Click to show/hide code block">Quoteless Attributes</a></td>
        <td align="right"><a href="http://blog.astrumfutura.com/#codesyntax_2" title="Show code only"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/#codesyntax_2" title="Print code"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Show plugin information"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" alt="image" /></a>&nbsp;</td>
      </tr>
    </table>
  </div>
  <div id="wpshdi_2" class="wp-synhighlighter-inner" style="display: block;">
    <div class="php" style="font-family:monospace;">
      <ol>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <a href="http://www.php.net/header"><span style="color: #990000;">header</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Content-Type: text/html; charset=UTF-8'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;!DOCTYPE html&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$input</span> <span style="color: #339933;">=</span> <span style="color: #0000cc; font-style: italic;">&lt;&lt;&lt;INPUT</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">faketitle onmouseover=alert(/Meow!/);</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">INPUT</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$output</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/htmlspecialchars"><span style="color: #990000;">htmlspecialchars</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$input</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">ENT_QUOTES</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;html&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;head&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;title&gt;Quoteless Attribute&lt;/title&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/head&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;body&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;div&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">        &lt;span title=<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$output</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">            What's that latin placeholder text again?</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">        &lt;/span&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;/div&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/body&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/html&gt;</pre>
        </li>
      </ol>
    </div>
  </div>
</div>
<p>Without quotes delineating the attribute value, any space character (including any character a browser might interpret as a space &#8211; there are a lot!) allows the user to inject new attributes and values. As from the above, converting all quotes to entities is pointless if there are no quotes to start with! Our escaping doesn&#8217;t convert spaces or other space-interpreted characters into entities at all.</p>
<p>By now, you should see the obvious. All HTML attribute values MUST be quoted, and preferably DOUBLE quoted, in any scenario where you suspect untrusted input will be injected into an attribute value, or where htmlspecialchars() calls do not set the second parameter to use ENT_QUOTES. Believe it or not, using single quotes or no quotes remains popular and is perfectly valid under the new HTML5 spec. Some people even celebrate this new insanity. Keep an eye on any designers who look a bit wild eyed or spend too much time smiling while staring into empty space.</p>
<h1>Excuse Me, Sir, But Someone Ate My Quotes</h1>
<p>One of the great mysteries in escaping output is a common myth known as the Great ASCII Delusion (GAD). Those under the influence of this delusion, besides hearing voices in their head, have arrived at a belief that many character encodings are equivalent for the purposes of escaping those characters which have a special meaning for HTML, e.g ISO-8859-1 and UTF-8. Alas, this is untrue because the Mice created something called Internet Explorer 6 &#8211; a thoroughly shameful (but still commonly used) browser which corporations across the Planet continue to insist on using because buying new computers and upgrading operating systems just to use some fancy new Microsoft Office version is seen as a waste of shareholder funds.</p>
<p>Internet Explorer 6 is the bad boy of the XSS world since it&#8217;s vulnerable to ridiculous exploits no decent modern browser would dare associate with. Even Netscape would probably spit on it from beyond the grave. For example, have a go with this example using IE6 and PHP 5.3. If you need a testing version of all IE browsers since IE 5.5, you can download IETester from http://www.my-debugbar.com/ietester/index_all.php and use it from Windows. Try hard, I know Windows is bad and the new Tablet makeover for Windows 8 makes you feel ill, but it&#8217;s important to see these examples in action.</p>
<div id="wpshdo_3" class="wp-synhighlighter-outer">
  <div id="wpshdt_3" class="wp-synhighlighter-expanded">
    <table border="0" width="100%">
      <tr>
        <td align="left" style="width: 80%;"><a name="#codesyntax_3"></a><a id="wpshat_3" class="wp-synhighlighter-title" href="http://blog.astrumfutura.com/#codesyntax_3" title="Click to show/hide code block">Source code</a></td>
        <td align="right"><a href="http://blog.astrumfutura.com/#codesyntax_3" title="Show code only"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/#codesyntax_3" title="Print code"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Show plugin information"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" alt="image" /></a>&nbsp;</td>
      </tr>
    </table>
  </div>
  <div id="wpshdi_3" class="wp-synhighlighter-inner" style="display: block;">
    <div class="php" style="font-family:monospace;">
      <ol>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <a href="http://www.php.net/header"><span style="color: #990000;">header</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Content-Type: text/html; charset=UTF-8'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;!DOCTYPE html&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">/**</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;* You could also subsititute xC0 or any other impacted character</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;* above ASCII number 192</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;*/</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$input1</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'fakeimage'</span><span style="color: #339933;">.</span><a href="http://www.php.net/chr"><span style="color: #990000;">chr</span></a><span style="color: #009900;">&#40;</span>192<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$input2</span> <span style="color: #339933;">=</span> <span style="color: #0000cc; font-style: italic;">&lt;&lt;&lt;INPUT2</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">onerror=alert(/Meow!/)//</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">INPUT2</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$output1</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/htmlspecialchars"><span style="color: #990000;">htmlspecialchars</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$input1</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">ENT_QUOTES</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$output2</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/htmlspecialchars"><span style="color: #990000;">htmlspecialchars</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$input2</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">ENT_QUOTES</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;html&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;head&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;title&gt;Swallowed Quotes&lt;/title&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/head&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;body&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;div&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">        &lt;img src=&quot;http://example.com/images/<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$output1</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">        title=&quot;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$output2</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;/div&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/body&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/html&gt;</pre>
        </li>
      </ol>
    </div>
  </div>
</div>
<p>With the above example, something very weird happens. Using ASCII character number 192 just before a double quote in a document being interpreted as UTF-8 results in the double quote&#8230;vanishing in IE6. Seriously, it&#8217;s there but not there. Obviously the Mice are behind it &#8211; no Human could possibly defy Physics like this!</p>
<p>This allows an attacker to once again break out of the HTML attribute they can inject values into. Using a coincidental opportunity to inject a second free text string nearby which a browser will concatenate to the broken out attribute value of the first, you get an effective XSS combo attack.</p>
<p>This IE6 quirk even bypasses the call to htmlspecialchars() which, as explained above, defaults to the ISO-8859-1 character encoding for PHP 5.3 or less. If the Great ASCII Delusion were not a fabrication of someone&#8217;s imaginative wishful thinking, this should not be possible. Not to be too harsh though, this weirdness is due primarily to a bug in IE6&#8242;s treatment of the various character encodings where you can trick the browser into thinking something like xC0 (in hex) is the start of a multi-byte character thus swallowing the next ASCII character (the double quote).</p>
<p>To fix the above weirdness, you must make sure that escaping is done using the same character encoding that the document is being served as. The above HTML document is identifying itself as being UTF-8 but the default htmlspecialchars() encoding is ISO-8859-1 in PHP 5.3 &#8211; there&#8217;s obviously something not agreeing there! This brings us to the absolutely perfect use (well, almost) of htmlspecialchars(), the golden rule, the Word of The Supreme Spaghetti Monster, the bringer of frustration to XSS attackers:</p>
<p>Always set the third parameter to htmlspecialchars(), set it correctly, and make sure your document is never served with a mismatched or invalid character encoding! Don&#8217;t expect some theoretically perfect world to magically appear &#8211; browsers are filthily efficient at doing weird things you don&#8217;t expect.</p>
<p>I suppose I have to mention that most versions of IE have similar issues with other character encodings such as BIG5 and Shift-JIS. You can test your IE versions using http://ha.ckers.org/weird/variable-width-encoding.cgi to see what characters can be used across different character encodings. Believe it or not, these character encodings are actually still being used and, for some strange reason, people from China and Japan do use PHP.</p>
<p>If you want to be completely paranoid, you can either check the input for invalid UTF-8 (Drupal and HTMLPurifier have reusable functions/classes for this), and/or run it through a conversion function which should theoretically filter out the naughty bits:</p>
<pre>$input = mb_convert_encoding($input, 'UTF-8', 'UTF-8');</pre>
<p>This is probably a good idea for older PHP versions pre 2010 or earlier but recent PHP versions have specifically improved htmlspecialchars() to disallow invalid characters such as the above (if you set the right character encoding!). You should be aware, though, that htmlspecialchars() may still return blank strings on certain malformed input and, since PHP 5.4, will not issue any warnings about this.</p>
<h1>I Broke It! I Broke It!</h1>
<p>Before you think htmlspecialchars() is getting off lightly, there is one minor quibble. We&#8217;ll keep picking on Internet Explorer 6 for the rest of this article since it&#8217;s so easy to exploit.</p>
<div id="wpshdo_4" class="wp-synhighlighter-outer">
  <div id="wpshdt_4" class="wp-synhighlighter-expanded">
    <table border="0" width="100%">
      <tr>
        <td align="left" style="width: 80%;"><a name="#codesyntax_4"></a><a id="wpshat_4" class="wp-synhighlighter-title" href="http://blog.astrumfutura.com/#codesyntax_4" title="Click to show/hide code block">Source code</a></td>
        <td align="right"><a href="http://blog.astrumfutura.com/#codesyntax_4" title="Show code only"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/#codesyntax_4" title="Print code"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Show plugin information"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" alt="image" /></a>&nbsp;</td>
      </tr>
    </table>
  </div>
  <div id="wpshdi_4" class="wp-synhighlighter-inner" style="display: block;">
    <div class="php" style="font-family:monospace;">
      <ol>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <a href="http://www.php.net/header"><span style="color: #990000;">header</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Content-Type: text/html; charset=UTF-8'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;!DOCTYPE html&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$input1</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'fakeimage'</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #660099; font-weight: bold;">xC0</span>&quot;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$input2</span> <span style="color: #339933;">=</span> <span style="color: #0000cc; font-style: italic;">&lt;&lt;&lt;INPUT2</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">onerror=alert(/Meow!/)//</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">INPUT2</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">/**</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;* If you think PHP 5.4 will save you - empty strings make it guess the encoding</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;* or use the default_charset value from php.ini. You sure everyone on the whole</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;* planet uses UTF-8? Under 5.3 - empty strings === default encoding.</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;*/</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$encoding</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// from outside source or unvalidated variable</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$output1</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/htmlspecialchars"><span style="color: #990000;">htmlspecialchars</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$input1</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">ENT_QUOTES</span><span style="color: #339933;">,</span> <span style="color: #000088;">$encoding</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$output2</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/htmlspecialchars"><span style="color: #990000;">htmlspecialchars</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$input2</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">ENT_QUOTES</span><span style="color: #339933;">,</span> <span style="color: #000088;">$encoding</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;html&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;head&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;title&gt;Swallowed Quotes&lt;/title&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/head&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;body&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;div&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">        &lt;img src=&quot;http://example.com/images/<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$output1</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">        title=&quot;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$output2</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">    &lt;/div&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/body&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;/html&gt;</pre>
        </li>
      </ol>
    </div>
  </div>
</div>
<p>Setting the third $encoding parameter of htmlspecialchars() to an empty string in PHP 5.4 will set the encoding to be auto-detected, grabbed from the php.ini value of default_charset, or guessed from the current locale (in that order). Be very careful under PHP 5.4 NEVER to let this happen. Don&#8217;t leave your escaping parameters to chance.</p>
<p>Use empty() or strlen(), for example, to spot this issue if accepting encodings from another source or variable that might allow for empty strings. Again, this behaviour is very secure and there&#8217;s nothing wrong with it whatsoever. Oh, who am I kidding&#8230; This is the dumbest parameter behaviour ever invented. NULL means use the default encoding; blank string means play a guessing game. Even Vogon poetry pales in comparison to such nonsense. One slip and an empty parameter string can rip apart this house of cards because who knows which character encoding will be used.</p>
<p>Oooh, I wonder what this does under PHP 5.3&#8230; Yes, er, don&#8217;t allow blank encoding parameter strings under PHP 5.3 either. Setting an empty string in PHP 5.3 is interpreted as setting the default character encoding, i.e. ISO-8859-1, instead of triggering the expected warning about an unsupported encoding.</p>
<p>So, be careful kids. When setting the encoding for htmlspecialchars() do a safety check to make sure it&#8217;s not an empty string you are passing in. Keep it predictable and consistent.</p>
<p>There&#8217;s also one other curious behaviour when using htmlspecialchars().</p>
<div id="wpshdo_5" class="wp-synhighlighter-outer">
  <div id="wpshdt_5" class="wp-synhighlighter-expanded">
    <table border="0" width="100%">
      <tr>
        <td align="left" style="width: 80%;"><a name="#codesyntax_5"></a><a id="wpshat_5" class="wp-synhighlighter-title" href="http://blog.astrumfutura.com/#codesyntax_5" title="Click to show/hide code block">Source code</a></td>
        <td align="right"><a href="http://blog.astrumfutura.com/#codesyntax_5" title="Show code only"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/#codesyntax_5" title="Print code"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" alt="image" /></a>&nbsp;<a href="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Show plugin information"><img style="border: 0 none; border: 0px;" src="http://blog.astrumfutura.com/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" alt="image" /></a>&nbsp;</td>
      </tr>
    </table>
  </div>
  <div id="wpshdi_5" class="wp-synhighlighter-inner" style="display: block;">
    <div class="php" style="font-family:monospace;">
      <ol>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <a href="http://www.php.net/header"><span style="color: #990000;">header</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Content-Type: text/html; charset=UTF-8'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&lt;!DOCTYPE html&gt;</pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">&lt;?php</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><a href="http://www.php.net/error_reporting"><span style="color: #990000;">error_reporting</span></a><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">E_ALL</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><a href="http://www.php.net/ini_set"><span style="color: #990000;">ini_set</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'display_errors'</span><span style="color: #339933;">,</span> 1<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$input1</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'fakeimage'</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #660099; font-weight: bold;">xC0</span>&quot;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$input2</span> <span style="color: #339933;">=</span> <span style="color: #0000cc; font-style: italic;">&lt;&lt;&lt;INPUT2</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">onerror=alert(/Meow!/)//</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0000cc; font-style: italic;">INPUT2</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">/**</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;* Invalid encoding makes htmlspecialchars() throw a warning but it continues</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;* the current operation anyway using the default encoding even if the default</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;* is an unsafe choice for the application. Don't allow invalid encodings!</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009933; font-style: italic;">&nbsp;*/</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$encoding</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'invalid-encoding'</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// from outside source or unvalidated variable</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$output1</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/htmlspecialchars"><span style="color: #990000;">htmlspecialchars</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$input1</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">ENT_QUOTES</span><span style="color: #339933;">,</span> <span style="color: #000088;">$encoding</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000088;">$output2</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/htmlspecialchars"><span style="color: #990000;">htmlspecialchars</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$input2</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">ENT_QUOTES</span><span style="color: #339933;">,</span> <span style="color: #000088;">$encoding</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
        <pre style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
        </li>
        <li style="font-weight: normal; vertical-align:top;">
   </div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Mon, 12 Mar 2012 20:49:36 UT</pubDate>
            <guid>/entry/11/1194</guid>
        </item>
        <item>
            <title>Added to a feed: Some ZendView examples</title>
            <link>http://adamleach.co.uk/entry/some-zendview-examples-11-1195.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1195">
<p>With the release of Beta 3 of Zend Framework, we now have a significantly refactored the <tt>ZendView</tt> component.</p>
<p>One of the changes made is that there is a <tt>ViewModel</tt> object that is returned from a controller which contains the variables to be used within the view script along with meta information such as the view script to render. The really nice thing about ViewModels is that they can be nested and this is how the layout composes the action view script.</p>
<p>However, we can do many more interesting things than this and I've put together a <a href="http://zf2test.akrabat.com/">test application</a> with a controller showing some of the things that can be done.</p>
<p>Some examples:</p>
<p><strong>Change the layout in an action:</strong></p>
<pre class="phpcode"><span style="color: #0000BB">
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">public&nbsp;function&nbsp;</span><span style="color: #0000BB">differentLayoutAction</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Use&nbsp;a&nbsp;different&nbsp;layout
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">layout</span><span style="color: #007700">(</span><span style="color: #DD0000">'layout/different'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;</span><span style="color: #0000BB">ViewModel</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;}
</span>
</pre>
<p><strong>Create another view model at the layout's level:</strong></p>
<pre class="phpcode"><span style="color: #0000BB">
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">public&nbsp;function&nbsp;</span><span style="color: #0000BB">addAnotherViewModelToLayoutAction</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Use&nbsp;an&nbsp;alternative&nbsp;layout
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$layoutViewModel&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">layout</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$layoutViewModel</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setTemplate</span><span style="color: #007700">(</span><span style="color: #DD0000">'layout/another'</span><span style="color: #007700">);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;add&nbsp;an&nbsp;additional&nbsp;layout&nbsp;to&nbsp;the&nbsp;root&nbsp;view&nbsp;model&nbsp;(layout)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$sidebar&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">ViewModel</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$sidebar</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setTemplate</span><span style="color: #007700">(</span><span style="color: #DD0000">'layout/footer_one'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$layoutViewModel</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">addChild</span><span style="color: #007700">(</span><span style="color: #0000BB">$sidebar</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'footer'</span><span style="color: #007700">);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;</span><span style="color: #0000BB">ViewModel</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;}
</span>
</pre>
<p>I've created some other examples too, so I recommend that you grab the <a href="https://github.com/akrabat/ZF2TestApp">code from GitHub</a> and have a play! The code also includes a second module, <tt>Simple</tt>, which shows how to change the layout for an entire module.</p>
<p>You should also <a href="http://packages.zendframework.com/docs/latest/manual/en/zend.view.html#zend.view.quick-start">read the manual</a>!</p>
<p><a href="http://akrabat.com/?flattrss_redirect&amp;id=1850&amp;md5=9e041ce2b99f80bf3db8e2c48174fbb5" title="Flattr" target="_blank"><img src="http://akrabat.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>
</div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Mon, 12 Mar 2012 08:55:13 UT</pubDate>
            <guid>/entry/11/1195</guid>
        </item>
        <item>
            <title>My Top 3 #lastfm Artists: deadmau5 (52), Knife Party (10) &amp;amp; deadmau5 &amp;amp; Kaskade ...</title>
            <link>http://adamleach.co.uk/entry/my-top-3-lastfm-artists-deadmau5-52-knife-party-10--deadmau5--kask-14-384.html</link>
            <description><![CDATA[
<div class="twitter">
	<div class="title">My Top 3 #lastfm Artists: deadmau5 (52), Knife Party (10) &amp; deadmau5 &amp; Kaskade (1) #music <a href="http://t.co/9PBYJUMP" target="_blank">http://t.co/9PBYJUMP</a></div>
		
</div>
]]></description>
            <author>admin</author>
            <pubDate>Sun, 11 Mar 2012 23:24:46 UT</pubDate>
            <guid>/entry/14/384</guid>
        </item>
        <item>
            <title>Added to a feed: Sponsoring WhereCampEU 2012</title>
            <link>http://adamleach.co.uk/entry/sponsoring-wherecampeu-2012-11-1196.html</link>
            <description><![CDATA[
<div class="rss">
	<div  class="content" id="rss_1196">
<p></p>
<p>Fellow Nestordammers,</p>
<p>I'm delighted to announce that for the third year in a row we will be sponsoring <a href="http://wherecamp.eu">WhereCamp EU</a>! After London in 2010 and Berlin in 2011, ths year's event will be <a href="http://wherecamp.eu/blog/2012/02/wherecampeu-2012-dates-and-location/">in Amsterdam on April 28th and 29th</a>.</p>
<p>As always "camp" events are fairly free form, so it's hard to know exactly what to expect. But if past years are any guide there will be lively discussion, some interesting demos, and (just perhaps) a geobeer or three along the way. The pace of innovation in online cartography continues to accelerate, there is so much to discuss. Several members of the Nestoria team will be in attendance. We look forward to seeing you there.</p>
<p>Many thanks to the orgaisers and other sponsors for creating what is sure to be a great weekend. The best way to stay up to date on WhereCamp EU is of course via <a href="https://twitter.com/WhereCampEU">the twitter feed.</a></p>
<p>On a final note, if you're interested in all things web and geo but unfortunately can't make it to Amsterdam, consider joining us at <a href="http://geomobldn.org/">#geomob</a> events in London.</p>
<p>&nbsp;</p>
<p><a href="http://blog.nestoria.co.uk/sponsoring-wherecampeu-2012">Permalink</a> | <a href="http://blog.nestoria.co.uk/sponsoring-wherecampeu-2012#comment">Leave a comment&nbsp;&nbsp;&raquo;</a></p>
<div class="feedflare">
  <a href="http://feeds.feedburner.com/~ff/NestoriaBlog?a=8T-EElUhl8o:_ixQVBcWkzo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/NestoriaBlog?d=yIl2AUoC8zA" alt="image" style="border: 0px;" /></a> <a href="http://feeds.feedburner.com/~ff/NestoriaBlog?a=8T-EElUhl8o:_ixQVBcWkzo:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/NestoriaBlog?d=7Q72WNTAKBA" alt="image" style="border: 0px;" /></a>
</div>
<img src="http://feeds.feedburner.com/~r/NestoriaBlog/~4/8T-EElUhl8o" height="1" width="1" alt="image" /></div>
</div>]]></description>
            <author>admin</author>
            <pubDate>Sat, 10 Mar 2012 21:47:00 UT</pubDate>
            <guid>/entry/11/1196</guid>
        </item>
    </channel>
</rss>

