<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2863235049034941132</id><updated>2012-02-16T15:04:29.857-08:00</updated><category term='linux'/><category term='chrome extensions'/><category term='extensions'/><category term='chromium extensions'/><category term='respect'/><category term='advice'/><category term='twitter'/><category term='autoupdate'/><category term='obsessive nitpickery'/><category term='programming'/><category term='chromium'/><category term='fame'/><category term='games'/><category term='fun'/><category term='xpcom'/><category term='nerdsz'/><category term='firefox extensions'/><category term='JavaScript'/><category term='greasemonkey'/><category term='json schema'/><category term='fortune'/><category term='json'/><category term='dom-drag'/><category term='life'/><title type='text'>aaronboodman.com</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>20</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-1666098749292542105</id><published>2010-11-17T11:59:00.001-08:00</published><updated>2010-11-17T12:03:21.075-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='life'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='advice'/><title type='text'>Life: Updated instructions</title><content type='html'>Wow, there was tons of response to my &lt;a href="http://www.aaronboodman.com/2010/10/wherein-i-help-you-get-good-job.html"&gt;last post&lt;/a&gt;. I probably got 40 pings on IRC over the last week or so, and already have a few code reviews in progress by new contributors.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I want as many people as possible to get involved in programming, and Chromium in particular, but I can't help people individually at that rate. So I've updated the &lt;a href="http://www.aaronboodman.com/2010/10/wherein-i-help-you-get-good-job.html"&gt;instructions&lt;/a&gt; so that they require less manual steps by me.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm still more than happy to help people with questions once they get started.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Good luck!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-1666098749292542105?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/1666098749292542105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=1666098749292542105&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/1666098749292542105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/1666098749292542105'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2010/11/updated-instructions-for-getting-good.html' title='Life: Updated instructions'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-7052694582429466139</id><published>2010-11-11T17:28:00.000-08:00</published><updated>2010-11-11T18:03:54.096-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='json schema'/><category scheme='http://www.blogger.com/atom/ns#' term='chromium'/><category scheme='http://www.blogger.com/atom/ns#' term='json'/><title type='text'>C++ version of JSON Schema</title><content type='html'>Way back when we were starting the extensions project, I &lt;a href="http://www.aaronboodman.com/2009/04/yo-dawg.html"&gt;mentioned&lt;/a&gt; that we were using JSON schema for API validation.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This worked out &lt;a href="http://www.aaronboodman.com/2009/04/json-schema-part-2.html"&gt;pretty well&lt;/a&gt;, but the downside is that it was implemented in JavaScript, so it couldn't really be used effectively in Chrome's browser process (for somewhat obscure technical reasons it's complicated to run JavaScript in Chrome's main process -- we usually only run it in child processes).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So for a really long time, I've been wanting to re-implement it in C++ so that I could use it for work in the browser process too. Finally got around to it:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;a href="http://git.chromium.org/gitweb/?p=chromium.git;a=blob;f=chrome/common/json_schema_validator.h;hb=HEAD"&gt;json_schema_validator.h&lt;/a&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This only relies on Chromium's "&lt;a href="http://git.chromium.org/gitweb/?p=chromium.git;a=tree;f=base;hb=HEAD"&gt;base&lt;/a&gt;" library (which is really quite nice, btw), so it could conceivably be re-used by other projects. For example, I'm hoping that we can use it on the server side, in Chrome's &lt;a href="https://chrome.google.com/webstore"&gt;web store&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Figured it might be useful to someone else someday, too.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-7052694582429466139?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/7052694582429466139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=7052694582429466139&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/7052694582429466139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/7052694582429466139'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2010/11/c-version-of-json-schema.html' title='C++ version of JSON Schema'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-2459135986102740633</id><published>2010-10-20T00:38:00.001-07:00</published><updated>2011-01-22T03:29:17.350-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='life'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='advice'/><title type='text'>Wherein I help you get a good job</title><content type='html'>&lt;div&gt;&lt;i&gt;&lt;b&gt;Edit: &lt;/b&gt;The response to this post was kinda overwhelming. I've modified some of the steps below to require less manual work by me.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;/div&gt;From a recent &lt;a href="http://news.ycombinator.com/item?id=1808458"&gt;post&lt;/a&gt; on Hacker News:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Friends of mine are in the same position as this guy. They recently graduated with good degrees from a decent university with no illusions that finding a job was going to be anything but difficult. Rather than feel like they're owed a job the ones I know have spent hours _every_ day applying for jobs for the past (up to) 2 years with no success. Most of the time they get no reply from these companies (fair enough), but the few times they do get an interview someone else with more experience gets the job.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This sucks. There has been an education bubble over the last few decades that has told kids that all they need to do to guarantee success is go to a good school, make good grades, and get a degree. The result is that in many fields, there is vastly more supply than demand.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But there are a few fields that are hiring like crazy. One of them is mine: software engineering. Major tech firms cannot hire fast enough. And the barrier is low enough that you can start learning today, for free. If you work hard, you can know enough in a year to get a good starter job. It's been this way for more than a decade, and I suspect another decade of growth at least.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's the good news. Here's the bad news: It's going to be hard, and you'll need to give up on whatever you went to school for and spend a year learning something new.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But remember: the time you spent in school is a sunk cost. You can't get it back. Doing nothing just makes matters worse. I'm offering you a way to make progress today.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ok, still here? Here's how to get a good job programming in six easy steps:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. &lt;a href="http://dev.chromium.org/developers/how-tos/get-the-code"&gt;Download&lt;/a&gt; and &lt;a href="http://code.google.com/p/chromium/wiki/MacBuildInstructions"&gt;build&lt;/a&gt; Google Chrome&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;There are also build instructions for &lt;a href="http://dev.chromium.org/developers/how-tos/build-instructions-windows"&gt;Windows&lt;/a&gt; and &lt;a href="http://code.google.com/p/chromium/wiki/LinuxBuildInstructions"&gt;Linux&lt;/a&gt; if you prefer&lt;/li&gt;&lt;li&gt;If you don't like Chrome, you can also work on &lt;a href="https://developer.mozilla.org/En/Developer_Guide/Source_Code"&gt;Firefox&lt;/a&gt; or &lt;a href="http://webkit.org/"&gt;Safari&lt;/a&gt;, but the rest of these instructions are optimized for Chrome since that's what I'm familiar with.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;2. Browse the bug database to find something to work on. Here are some useful queries:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/chromium/issues/list?q=feature:extensions,apps+label:helpwanted"&gt;feature:extensions,apps label:helpwanted&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/chromium/issues/list?q=feature:extensions,apps+type:cleanup"&gt;feature:extensions,apps type:cleanup&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;I can personally review changes in these areas, and I try and keep these lists well-stocked with good starter bugs. You can also work in other areas, but you may have to find someone else to review your work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If a bug has an owner assigned, but there has been no activity for a week or so, comment on the bug and ask whether you can take it over.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;3. Once you have picked a bug, comment on it saying you're going to work on it. If it is in feature:extensions,apps,  I will get notified of your comment, and will mark the bug as owned by me so nobody else grabs it. I will probably also add some comments about where to start.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;4. Study the code, referring to a &lt;a href="http://www.cplusplus.com/doc/tutorial/"&gt;C++ tutorial&lt;/a&gt; as needed. You may also want to buy an actual paper book on the subject. Make the changes required to fix the bug. Once you have it working, send me (aa-at-chromium-dot-org) a &lt;a href="http://dev.chromium.org/developers/contributing-code"&gt;code review&lt;/a&gt; with your changes.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;5. Repeat steps 2 and 3 about 50 times.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;6. Update your resume to say that you are a junior software engineer and you have contributed significant code to Google Chrome (or Firefox or whatever), and provide a link &lt;a href="http://git.chromium.org/gitweb/?p=chromium.git/.git;a=search;s=aa@chromium.org;st=author"&gt;showing your work&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ok, so these steps aren't really "easy". Some of them will take months. Just getting Chromium compiling is going to take awhile. I've purposely been vague on the details so you can figure it out on your own. You'll need ingenuity, a search engine, and a lot of patience.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But I guarantee, 100%, for-sure, that if you complete my program, you will be able to easily find a good starting job programming.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hiring programmers is super hard. It's nearly impossible to evaluate whether someone is good without examples of their work. By working on open source projects like the ones I've listed, you make it easy for hiring managers. They can see what you can do and how you work with others.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's nothing stopping you from making this happen. It's going to be hard, but you can do it. And there's lots of people that are willing to help once you take the first few steps.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-2459135986102740633?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/2459135986102740633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=2459135986102740633&amp;isPopup=true' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2459135986102740633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2459135986102740633'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2010/10/wherein-i-help-you-get-good-job.html' title='Wherein I help you get a good job'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-1126383069899443877</id><published>2010-01-28T00:12:00.000-08:00</published><updated>2010-01-28T00:35:17.174-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='chrome extensions'/><title type='text'>Academic paper on Chromium extensions</title><content type='html'>&lt;a href="http://www.eecs.berkeley.edu/Pubs/TechRpts/2009/EECS-2009-185.html"&gt;Protecting Browsers from Extension Vulnerabilities&lt;/a&gt; is a paper that covers some of the interesting security features of the Chromium extension system.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The isolated worlds feature that I wrote about &lt;a href="http://www.aaronboodman.com/2009/04/content-scripts-in-chromium.html"&gt;earlier&lt;/a&gt; is described toward the end. Isolated worlds separate each JavaScript program that has access to a web page's DOM. Each program can modify the DOM and see changes made by other programs, but programs cannot exchange JavaScript references. This setup prevents privileges from accidentally leaking between programs. Isolated worlds are now implemented directly in WebKit (thanks to Adam Barth), so they could show up in other WebKit applications in the future.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My other favorite feature is that an extension's unique ID is a public key. The extension is signed with the corresponding private key, which means it is impossible to have ID collisions. Even if a developer copies an existing extension to get started, he won't be able to copy the extension's ID because he would need the private key in order to sign it.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-1126383069899443877?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/1126383069899443877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=1126383069899443877&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/1126383069899443877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/1126383069899443877'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2010/01/academic-paper-on-chromium-extensions.html' title='Academic paper on Chromium extensions'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-5122250056746136088</id><published>2009-12-24T14:35:00.000-08:00</published><updated>2009-12-24T16:16:54.545-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Hey I used that license, too</title><content type='html'>Was amused by Evan's &lt;a href="http://community.livejournal.com/evan_tech/270349.html"&gt;take&lt;/a&gt; on JSMin's software license. Apparently all of Crockford's work includes the clause "&lt;a href="http://wonko.com/post/jsmin-isnt-welcome-on-google-code"&gt;The software shall be used for Good, not Evil&lt;/a&gt;" in addition the standard MIT license text.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I think at one point I saw this, internalized it, and spat it back out as "&lt;a href="http://youngpup.net/projects/dom-drag/license.txt"&gt;This code is public domain. Please use it for good, not evil.&lt;/a&gt;"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I know that this stuff is really serious business to some people, and they get frustrated by these random acts of frivolity. "Don't you know," they say with a stern face, "software licenses are no place for fun and games".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Pfffft. The license is awesome. I appreciated the joke when I first saw it, and am appreciating the ongoing humor it is providing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I do see how it would prevent some organizations from using the code. Mostly those that have become large, risk-averse, and so disconnected from the community that they are actually, honestly afraid that Crockford is going to come after them for using JSMin for evil.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sadly, Google apparently now falls into that bucket.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-5122250056746136088?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/5122250056746136088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=5122250056746136088&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/5122250056746136088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/5122250056746136088'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2009/12/hey-i-used-that-license-too.html' title='Hey I used that license, too'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-6147883252916416049</id><published>2009-07-17T00:55:00.001-07:00</published><updated>2009-07-17T01:11:39.413-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xpcom'/><category scheme='http://www.blogger.com/atom/ns#' term='firefox extensions'/><title type='text'>Bundling multiple versions of binary XPCOM components</title><content type='html'>I happened to come up with what I think is a clever hack for getting around a sticky compatibility problem in Firefox extensions.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The problem is that if your extension includes a binary XPCOM component that uses unfrozen interfaces (and it is hard not to, lots of things are unfrozen), then it is highly likely that you will have to recompile your component for each new version of the Gecko SDK (and therefore most new major versions of Fierfox).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Mozilla wiki proposed the idea of using a "stub component" to sniff the environment version and load the right XPCOM component, but this is pretty complex to implement.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I realized that you can just use JavaScript to do the same, and it is &lt;a href="http://code.google.com/p/gears/source/browse/trunk/gears/base/firefox/static_files/components/stub.js"&gt;trivial&lt;/a&gt;. Hope this helps someone else out (I've also updated the wiki).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-6147883252916416049?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/6147883252916416049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=6147883252916416049&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/6147883252916416049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/6147883252916416049'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2009/07/bundling-multiple-versions-of-binary.html' title='Bundling multiple versions of binary XPCOM components'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-8284954802042998066</id><published>2009-06-26T09:52:00.000-07:00</published><updated>2009-06-26T09:59:42.206-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='respect'/><title type='text'>The designs of dustincurtis.com</title><content type='html'>Are &lt;a href="http://www.dustincurtis.com/"&gt;beautiful&lt;/a&gt;.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;a href="http://dustincurtis.com/sleep.html"&gt;&lt;img style="width: 300px; height: 186px; border:2px solid" src="http://3.bp.blogspot.com/_wvU8sfXEBm8/SkT66sduZyI/AAAAAAAAAM8/orCdeLBZlRw/s400/3.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://dustincurtis.com/the_filter.html"&gt;&lt;img style="width: 300px; height: 186px; border:2px solid" src="http://3.bp.blogspot.com/_wvU8sfXEBm8/SkT6V09FY5I/AAAAAAAAAMs/3MsRJ7iMSgE/s400/2.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://dustincurtis.com/the_moment_i_became_fascinated_with_medicine.html"&gt;&lt;img style="width: 300px; height: 186px; border:2px solid" src="http://2.bp.blogspot.com/_wvU8sfXEBm8/SkT6VpFVlDI/AAAAAAAAAMk/dEHUKY0XyxQ/s400/1.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;I say &lt;i&gt;designs &lt;/i&gt;because I just realized that each article has its own unique design.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I read most of these when they were posted, but I think the fact that they were posted relatively far apart made me miss the fact that each one has a different look.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some of the designs are very intricate and clearly were a lot of work. For example, check out &lt;a href="http://dustincurtis.com/about.html"&gt;about.html&lt;/a&gt;. Tying things together is a common header and footer that brings continuity and allows you to navigate between articles.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I attempted to do something like this once for my own blog, but found that I simply did not have the time and energy to come up with a good design for every single post.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm glad that someone else did, and I'm looking forward to the next article.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-8284954802042998066?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/8284954802042998066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=8284954802042998066&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/8284954802042998066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/8284954802042998066'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2009/06/designs-of-dustincurtiscom.html' title='The designs of dustincurtis.com'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wvU8sfXEBm8/SkT66sduZyI/AAAAAAAAAM8/orCdeLBZlRw/s72-c/3.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-4244911703074213829</id><published>2009-04-15T01:00:00.000-07:00</published><updated>2009-04-15T01:20:48.066-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='obsessive nitpickery'/><category scheme='http://www.blogger.com/atom/ns#' term='chromium extensions'/><title type='text'>JSON Schema, part 2</title><content type='html'>&lt;div&gt;So the JSON Schema stuff worked out:&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;chromium.tabs.createTab = function(tab, callback) {&lt;br /&gt;  validate(arguments, arguments.callee.params);&lt;br /&gt;  sendRequest(CreateTab, tab, callback);&lt;br /&gt;};&lt;br /&gt;chromium.tabs.createTab.params = [&lt;br /&gt;  {&lt;br /&gt;    type: "object",&lt;br /&gt;    properties: {&lt;br /&gt;      windowId: chromium.types.optPInt,&lt;br /&gt;      url: chromium.types.optStr,&lt;br /&gt;      selected: chromium.types.optBool&lt;br /&gt;    },&lt;br /&gt;    additionalProperties: false&lt;br /&gt;  },&lt;br /&gt;  chromium.types.optFun&lt;br /&gt;];&lt;br /&gt;&lt;br /&gt;--&lt;a href="http://codereview.chromium.org/66006/diff/1087/1101"&gt;http://codereview.chromium.org/66006/diff/1087/1101&lt;/a&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;I'm really happy with how this came out because it means that all our APIs will get great error messages for free; it's not something that we'll have to think about (and therefore get wrong) on a case-by-case basis.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I tend to obsess about errors messages because they are basically the first-run experience for any library. No matter how well designed, people are going to typically call your API wrong the first time, especially in a loosely-typed language like JavaScript. What happens in that case? Does the API stare blankly back at them, leaving them to wonder if their code is even running? Or does it helpfully tell them what they did wrong?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Chromium APIs will give errors. Specifically, they will retort something like:&lt;/div&gt;&lt;pre&gt;&lt;b&gt;Invalid value for parameter 0. Property windowId: expected integer, got string.&lt;/b&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-4244911703074213829?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/4244911703074213829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=4244911703074213829&amp;isPopup=true' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/4244911703074213829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/4244911703074213829'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2009/04/json-schema-part-2.html' title='JSON Schema, part 2'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-3391134500847869102</id><published>2009-04-13T02:01:00.000-07:00</published><updated>2009-04-13T16:26:25.294-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='chromium extensions'/><title type='text'>Content Scripts in Chromium</title><content type='html'>&lt;div&gt;Here's an interesting factoid about browser extensions: lots of them are not about extending the browser at all. By my count, about 75% of the this week's &lt;a href="https://addons.mozilla.org/en-US/firefox/browse/type:1/cat:all?sort=popular"&gt;top 20&lt;/a&gt; Firefox extensions are more about extending the web content rendered by the browser than extending the browser itself. Similar trends exist in other browser extension systems.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Chromium extensions will be able to interact with web content too, using a feature we're calling &lt;i&gt;content scripts&lt;/i&gt; (we've gone around and around on the name, this may not be final).  The code for this is at a pretty good stopping point now, so I wanted to pause and write down what we did, why we did it, and some ideas I have for future improvements.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;If you want to try it out, you can check out the beginnings of our &lt;a href="http://dev.chromium.org/developers/design-documents/extensions/howto"&gt;Extension Tutorial&lt;/a&gt;, which covers most of what I'll talk about here.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, some background on the feature...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Content scripts are basically the same thing as Greasemonkey scripts, with some important improvements.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You register your content scripts declaratively in your extension's manifest, like this:&lt;/div&gt;&lt;pre&gt;{&lt;br /&gt;  "name": "My first extension",&lt;br /&gt;  "description": "The first extension that I made",&lt;br /&gt;  "version": "1.0",&lt;br /&gt;  "content_scripts": [&lt;br /&gt;    {&lt;br /&gt;      "matches": ["http://www.google.com/*", "http://mail.google.com/"],&lt;br /&gt;      "css": ["foo.css", "bar.css"],&lt;br /&gt;      "js": ["hot.js", "dog.js"],&lt;br /&gt;      "run_at": "document_start"&lt;br /&gt;    }&lt;br /&gt;  ]&lt;br /&gt;}&lt;/pre&gt;The syntax for &lt;a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/url_pattern.h"&gt;matching URLs&lt;/a&gt; is slightly different than in Greasemonkey. The reason for this is that we wanted to eliminate a common bug in Greasemonkey scripts, where people accidentally match URLs more loosely than they intend. A classic example is the common Greasemonkey pattern &lt;i&gt;&lt;b&gt;@include *.google.com*&lt;/b&gt;&lt;/i&gt;, which matches&lt;i&gt; every&lt;/i&gt; domain, not just google.com and its subdomains.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The matching syntax used in content scripts separates the domain portion of the pattern from the path portion, making it more explicit which sites a script will run on. One way we could use this is to someday do UI like this:&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;==============================================&lt;br /&gt;Install 'My extension'?&lt;br /&gt;----------------------------------------------&lt;br /&gt;This extension will be able to interact with&lt;br /&gt;web pages on:&lt;br /&gt;&lt;br /&gt;www.google.com&lt;br /&gt;mail.google.com&lt;br /&gt;&lt;br /&gt;                            [ok] [cancel]&lt;br /&gt;==============================================&lt;/pre&gt;&lt;br /&gt;Other minor feature differences:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;A content script can consist of multiple physical JavaScript files or CSS files, and it can also reference images or other resources included in the extension by URL.&lt;/li&gt;&lt;li&gt;Content scripts support "early injection", which allows them to request being injected before any nodes have been added to the document by using the optional "run_at" key.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Execution Environment&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To understand the execution environment for content scripts, it helps to first understand the execution environment of normal web page JavaScript.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All JavaScript is defined in a &lt;i&gt;context&lt;/i&gt;. Each DOM window gets its own context, one purpose of which is to hold the prototypes of all the global objects (Object, Array, String, and so-on). This is why when you extend Array.prototype in one frame, it doesn't affect Arrays created in other frames.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Importantly, you can call functions and access objects across contexts. This happens normally when you do something like &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;window.frames['otherframe'].someFunction()&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a diagram that explains the relationship between the various objects in pretty picture form (thanks, &lt;a href="http://www.gliffy.com/"&gt;Gliffy&lt;/a&gt;!):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div align="center"&gt;&lt;img style="width: 213px; height: 400px;" src="http://1.bp.blogspot.com/_wvU8sfXEBm8/Sdllw_nKfTI/AAAAAAAAAME/eUttVLKNvjE/s400/a.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5321396327098776882" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Each context also has a single global object. When you access global variables in a JavaScript program, you are really interacting with the properties of this global object. In HTML, the global object is of course the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Window&lt;/span&gt; object.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To make property hiding work, in Chromium's implementation, the global object is not actually the same JavaScript object that represents ("wraps") the C++ DOMWindow. There is actually a separate JavaScript object whose &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;__proto__&lt;/span&gt; points to that object. When you define global variables, it is this object where the properties are actually defined.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ok, so how do content scripts fit into this?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Content scripts run in a very similar-looking environment. They run in a separate context, and have a separate global object. But that global object's &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;__proto__&lt;/span&gt; points at the same JS object that represents the Window.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div align="center"&gt;&lt;img style="width: 361px; height: 400px;" src="http://4.bp.blogspot.com/_wvU8sfXEBm8/Sdj1ptpjsGI/AAAAAAAAALk/JBxkpyH08i4/s400/b.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5321273056715583586" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So content scripts get their own global scope and their own set of prototypes. Variables defined in the web page won't be "visible" by default in content scripts, and the same is true in reverse. Other than that, the environment for content scripts is exactly the same as for normal JavaScript running in web pages. Writing content scripts should be exactly the same as writing JavaScript for web pages.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sometimes it is useful to access the page's global variables. For example, in Gmail there is &lt;a href="http://code.google.com/p/gmail-greasemonkey/wiki/GmailGreasemonkey10API"&gt;an API&lt;/a&gt; that allows Greasemonkey scripts to drive some parts of the UI. To allow this kind of functionality, the content script envionment has a special &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;contentWindow&lt;/span&gt; global variable defined that can be used to access the global scope of the page's JavaScript.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Permissions&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Another difference from Greasemonkey is the model for accessing privileged APIs. Greasemonkey scripts have direct access to some privileged APIs. The most popular of these is &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;GM_xmlhttpRequest&lt;/span&gt;, which provides access to origins other than the one for the current document. These APIs are very useful, but there have been bugs where they leaked into web content, which was bad.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In order to prevent this from being possible, Chromium extensions are split into two main pieces: a privileged part (I'll call it just 'the extension' from now on) that has access to special powerful APIs, and an unprivileged part (the content script) that runs in the renderer and has no special APIs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The two parts cannot interact directly. In fact, they run in separate OS processes, so direct interaction is impossible. The only way they can communicate is via message passing APIs, similar to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;postMessage()&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div align="center"&gt;&lt;img src="http://4.bp.blogspot.com/_wvU8sfXEBm8/Sdlo43X5gMI/AAAAAAAAAMU/jVyI82plQVo/s400/c.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5321399760861102274" style="width: 400px; height: 302px; " /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;(&lt;b&gt;NOTE:&lt;/b&gt; The implementation of content script messaging is still in progress and is incomplete in current trunk and dev builds)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It is the extension developer's responsibility to send only specific messages to the extension process from the renderer, and to validate those messages carefully. Extension developers need to be aware that malicious web pages could send them messages exactly the same way their content scripts can.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This design is modeled after the way Chromium itself works, where the renderers are untrusted and have to send messages to the browser process to get interesting work done.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Future Directions&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have a couple ideas for where I'd like to take this next...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Idea 1: Completely separate content scripts and page JavaScript&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Right now, the way that JavaScript access to the DOM is implemented, there is essentially a global table of JavaScript wrappers for each C++ DOM object. Whenever code needs to find the JS object for a given C++ object, it consults this table:&lt;/div&gt;&lt;div align="center"&gt;&lt;br /&gt;&lt;img style="width: 320px; height: 184px;" src="http://2.bp.blogspot.com/_wvU8sfXEBm8/Sdj3S6SY07I/AAAAAAAAAL0/FJcvh7Ia-n4/s320/d.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5321274863994327986" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This single table creates a bridge between any two JavaScript contexts that have access to the same DOM nodes. For example if page JavaScript does something like &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;document.body.onclick = function() { ... }&lt;/span&gt;, any other code that has access to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;document.body&lt;/span&gt; will also have access to the onclick function handler that the page JavaScript defined .&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This makes sense for web pages, where you want frames in the same origin to see the same sets of JavaScript variables. But for content scripts, it would be nice to wall these two worlds off from each other. It is relatively infrequent for content scripts to need to see the JavaScript enironment fo pages. It is more typical to only need access to the DOM.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In order to isolate content scripts from page JavaScript, we'd have to have separate mapping tables: one for the page JavaScript, and one for each content script. A C++ DOM node could have multiple wrappers, one for each of these "worlds". Then, when we needed to get a JavaScript object for a particular C++ object, we'd decide which table to look in based on which context the calling code was running in. Every context could only be in one "world".&lt;/div&gt;&lt;div align="center"&gt;&lt;img style="width: 301px; height: 400px;" src="http://3.bp.blogspot.com/_wvU8sfXEBm8/Sdj3Y9epWUI/AAAAAAAAAL8/_vYrUYv1qN8/s400/e.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5321274967930263874" /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;We could even add assertions to the JavaScript engine that worlds are never bridged. That way if we ever had a bug, in the worst case we'd crash the renderer, not have a security problem.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If we can wall these worlds off from each other, then we can offer some increased privileges to content scripts directly, because we'd be confident that they couldn't leak to web content. You'd no longer have to go to the extension process to get cross-origin XHR, for example. This would also have the advantage of not requiring extension developers to carefully validate their messages, since we would know that page JavaScript could not send extensions messages.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We'd still probably need content scripts as they exist today if you want to interact with the JS defined by the page (for example for the Gmail API). But lots of use cases don't need that, and this idea would decrease complexity for those cases.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Idea 2: DOM Access from Extension Processes&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another idea is to offer some form of DOM access directly to extension processes. There is a team in Chromium working on an out-of-process version of the web inspector. This will clearly need some form of DOM access to work, so we can probably reuse what they do to give extension developers the ability interact with page DOM directly from their extension process. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I can imagine something simple based on querySelectorAll(). You ask for some nodes based on a CSS expression, get back a snapshot, and then send some updates. Of course, there are problems with races: the nodes might be gone by the time you send the update. But I think in most cases this would work pretty nicely I think. Again, I think we'd want to keep content scripts as they are today for more complex needs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold; "&gt;Yawn... Greasemonkey is great, but when do we get real extensions?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I know, I know. These aren't "real" extensions. You want to know when you'll be able to put things in the Chrome UI. Good news: that is &lt;a href="http://codereview.chromium.org/56122"&gt;well underway&lt;/a&gt;. Hopefully my next blog post will be about how to add "toolstrips" to Chromium.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Until then, have a look at content scripts and let us know what you think.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-3391134500847869102?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/3391134500847869102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=3391134500847869102&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/3391134500847869102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/3391134500847869102'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2009/04/content-scripts-in-chromium.html' title='Content Scripts in Chromium'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_wvU8sfXEBm8/Sdllw_nKfTI/AAAAAAAAAME/eUttVLKNvjE/s72-c/a.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-2909176875169765973</id><published>2009-04-05T20:41:00.000-07:00</published><updated>2009-04-05T20:49:38.127-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='extensions'/><category scheme='http://www.blogger.com/atom/ns#' term='chromium'/><title type='text'>Yo dawg...</title><content type='html'>So on the extensions project, I've been working on what I think is the somewhat novel idea of API non-design.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To be more specific, I'm using the CRUD pattern as a starting point for all the major sub-systems' APIs. My hope is that this will have a number of positive effects:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Minimize API design hand-wringing&lt;/li&gt;&lt;li&gt;Provide a large base of functionality quickly&lt;/li&gt;&lt;li&gt;Make it easy for Chromium developers to add new APIs&lt;/li&gt;&lt;li&gt;Make it easy for extension developers to learn new APIs&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;We decided to use JSON heavily in the implementation. For example, the createTab() API looks like this:&lt;/div&gt;&lt;pre&gt;chromium.tabs.createTab({&lt;br /&gt; "url": "http://www.google.com/",&lt;br /&gt; "selected": true,&lt;br /&gt; "tabIndex": 3&lt;br /&gt;});&lt;/pre&gt;&lt;div&gt;So I got this all working for a few methods, and then I got to writing the validation code. I could write the code by hand, but that's so much work. And why bother when somebody has gone and invented &lt;a href="http://www.json.com/json-schema-proposal/"&gt;JSON Schema&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's right, it's a schema language for JSON. And of course it has a schema, written in JSON schema. Whee!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So we should be able to just declare the expected structure for our API parameters and push the validate() button. Probably there will have to be extra stuff around the edges, but this should get rid of a majority of the grunt work.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-2909176875169765973?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/2909176875169765973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=2909176875169765973&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2909176875169765973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2909176875169765973'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2009/04/yo-dawg.html' title='Yo dawg...'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-2879823862194639536</id><published>2009-03-18T23:00:00.000-07:00</published><updated>2009-03-18T23:06:40.120-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='chrome extensions'/><title type='text'>Not quite there yet</title><content type='html'>Matt jumped the gun on &lt;a href="http://www.mattcutts.com/blog/"&gt;announcing&lt;/a&gt; extensions.&lt;br /&gt;&lt;br /&gt;There's not much to see yet. You can --enable-extensions in developer builds, but all that gets you so far is Greasemonkey-type functionality, which was already more or less there via --enable-user-scripts.&lt;br /&gt;&lt;br /&gt;We're working on more toys, and you can bet we'll start blogging when there's something to play with. But not... quite... yet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-2879823862194639536?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/2879823862194639536/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=2879823862194639536&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2879823862194639536'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2879823862194639536'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2009/03/not-quite-there-yet.html' title='Not quite there yet'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-6845303903791486750</id><published>2009-02-24T01:36:00.001-08:00</published><updated>2009-02-24T01:40:22.296-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fortune'/><category scheme='http://www.blogger.com/atom/ns#' term='dom-drag'/><category scheme='http://www.blogger.com/atom/ns#' term='fame'/><title type='text'>If there ever were something w00t-worthy...</title><content type='html'>I forgot to post &lt;a href="http://www.whitehouse.gov/includes/dom-drag1.js"&gt;this&lt;/a&gt; back when I noticed it. Alas, they don't appear to be using it for anything.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I tracked down the element that is intended to be draggable, but I can't find any code that ever makes it visible.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Perhaps it is a feature that got killed, but not completely cleaned up. Or maybe it is used on the CMS side of the site, but is leaking a bit into the public.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I sent an email to webmaster@ and through their contact form, but got no reply :).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-6845303903791486750?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/6845303903791486750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=6845303903791486750&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/6845303903791486750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/6845303903791486750'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2009/02/if-there-ever-were-something-w00t.html' title='If there ever were something w00t-worthy...'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-2044490821840287176</id><published>2009-01-29T15:27:00.001-08:00</published><updated>2009-01-30T10:39:07.462-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='autoupdate'/><title type='text'>Update Fail</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wvU8sfXEBm8/SYI7d4sSIuI/AAAAAAAAAK4/7o_s82_eXVY/s1600-h/fail.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 271px;" src="http://2.bp.blogspot.com/_wvU8sfXEBm8/SYI7d4sSIuI/AAAAAAAAAK4/7o_s82_eXVY/s320/fail.png" alt="" id="BLOGGER_PHOTO_ID_5296861496361493218" border="0" /&gt;&lt;/a&gt;I'm a big believer in silent &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;autoupdates&lt;/span&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I know that it's a touchy issue, but I really believe that silent updates are the right thing for most users and for most software. Especially for consumer software connected to the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;internet&lt;/span&gt;, where security is especially important.&lt;br /&gt;&lt;br /&gt;This dialog is an example of why. Today, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Firefox&lt;/span&gt; showed me this, but since I was right in the middle of something at the time, I pressed "Later", without even really reading it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(Note: I don't mean to pick on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Firefox&lt;/span&gt; specifically. There is lots of software that works this way and it all irritates me equally. This just happened to be the &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;occasion&lt;/span&gt; that finally pushed me to blog. Also, it's harder for &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Firefox&lt;/span&gt; to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;autoupdate&lt;/span&gt; due to the huge number of add-&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;ons&lt;/span&gt; that are difficult to keep working across upgrades.)&lt;br /&gt;&lt;br /&gt;Usually when I'm using my computer, I'm doing something, so I typically dismiss dialogs like this. I know it isn't the brightest thing to do, but my experience is that these things often take a long time, force me to restart, and result in incompatibilities.&lt;br /&gt;&lt;br /&gt;I was talking about this yesterday with a friend and he put it well:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;It's basically saying, "Dear Mr. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;Boodman&lt;/span&gt;: Would you like to deal with our problems right now, or with your problems?"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Like most people, I'm usually going to go with my problems.&lt;br /&gt;&lt;br /&gt;I think it's the responsibility of the software vendors to keep their own code up to date. This is hard work, but the vendor is certainly better equipped to do it than I am.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The two places I feel that &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;autoupdate&lt;/span&gt; might not make sense are L&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;inux&lt;/span&gt; and corporate environments. I'm not hugely familiar with how Linux packages are kept up to date; I get the sense this still a largely manual process. But it seems like the distro might be better able to do autoupdates than the vendor, since the distro knows how to create binaries that will work best with the rest of the packages on the machine. In corporate environments, there is often an IT department whose job it is to keep your software up-to-date and functioning correctly.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Many people fear that software vendors would use &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;autoupdate&lt;/span&gt; to install additional unwanted products on their machine, or to update to a new buggy version. This is certainly possible, but I think it comes down to an issue of trust. When you install software, you are making a conscious decision to trust its creator to treat your privacy, data, and machine with respect. This is just the way client software works. As long as your are already trusting the software in all these ways, why not also trust it to keep itself up to date? If the vendor abuses your trust -- by violating your privacy, stealing your data, hogging resources on your machine, or installing new buggy software -- then fine, be upset about that. But when implemented well, I think that &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;autoupdate&lt;/span&gt; is a Good Thing.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-2044490821840287176?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/2044490821840287176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=2044490821840287176&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2044490821840287176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2044490821840287176'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2009/01/update-fail.html' title='Update Fail'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_wvU8sfXEBm8/SYI7d4sSIuI/AAAAAAAAAK4/7o_s82_eXVY/s72-c/fail.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-584775513584223144</id><published>2008-12-07T15:44:00.000-08:00</published><updated>2008-12-07T18:22:00.264-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='nerdsz'/><category scheme='http://www.blogger.com/atom/ns#' term='twitter'/><title type='text'>Introducing nerdsz</title><content type='html'>&lt;div&gt;For awhile now, I've been wanting something that could answer the question: &lt;span class="Apple-style-span" style="font-style: italic; "&gt;"What are my friends doing right now?"&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;There are probably already approximately 200 apps that do this, but for some reason I couldn't find one that worked the way I wanted. So instead I took the evening and hacked together &lt;a href="http://aaronboodman.com/nerdsz"&gt;nerdsz&lt;/a&gt; (pronounced &lt;span class="Apple-style-span" style="font-style: italic;"&gt;"nerds-zee"&lt;/span&gt;).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To use it, enter the &lt;a href="http://www.twitter.com/"&gt;twitter&lt;/a&gt; usernames of a group of people you're interested in. For example, &lt;a href="http://aaronboodman.com/nerdsz?aboodman,ev,biz,goldman"&gt;http://aaronboodman.com/nerdsz?aboodman,ev,biz,goldman&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;PS: You may be wondering about the name. For years now, I have been calling the group of friends I hang out with &lt;span class="Apple-style-span" style="font-style: italic;"&gt;the nerds&lt;/span&gt;. The &lt;span class="Apple-style-span" style="font-style: italic;"&gt;z &lt;/span&gt;is an inside joke that you probably have to work for Google to get. Sorry about that.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;PPS: This hack made possible by twitter's awesome, crazy-easy-to-use API. Thanks!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;PPPS: I also borrowed John Resig's &lt;a href="http://ejohn.org/projects/javascript-pretty-date/"&gt;PrettyDate&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-584775513584223144?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/584775513584223144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=584775513584223144&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/584775513584223144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/584775513584223144'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2008/12/introducing-nerdsz.html' title='Introducing nerdsz'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-2515365100621024759</id><published>2008-11-29T16:03:00.000-08:00</published><updated>2008-11-29T16:25:26.988-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='extensions'/><category scheme='http://www.blogger.com/atom/ns#' term='chromium'/><title type='text'>Extensions in Chromium</title><content type='html'>For the past few weeks, myself and a few others have been looking into how  extensions might work in Chromium. Last Wednesday, we published a &lt;a href="http://dev.chromium.org/developers/design-documents/extensions "&gt;design doc&lt;/a&gt;  with the beginning of our plan.&lt;br /&gt;&lt;br /&gt;If you're an extension developer or user, we'd love to hear your feedback. You can reach us at #chromium on irc.freenode.org or &lt;a href="http://groups.google.com/group/chromium-dev"&gt;chromium-dev@googlegroups.com&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-2515365100621024759?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/2515365100621024759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=2515365100621024759&amp;isPopup=true' title='27 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2515365100621024759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2515365100621024759'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2008/11/extensions-in-chromium.html' title='Extensions in Chromium'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>27</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-5836155778829750383</id><published>2008-11-11T21:26:00.000-08:00</published><updated>2008-11-13T00:56:42.253-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='chromium'/><title type='text'>Gmail in Chromium "Test Shell" on Linux</title><content type='html'>The other three guys in my office all work on Chromium for Linux. Right now, they are working on bringing up the "test shell". The test shell is a very simple browser that the Chromium development team uses for testing our integration with WebKit. It is the first step of porting Chromium to a new platform.&lt;br /&gt;&lt;br /&gt;Today, one of the linux guys &lt;a href="http://groups.google.com/group/chromium-dev/browse_thread/thread/c6a026e4aa210c5f"&gt;sent a message&lt;/a&gt; from Gmail in the linux test shell for the first time:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;From: "Dan Kegel" &lt;daniel.r.ke...@gmail.com&gt;&lt;br /&gt;To: chromium-dev@googlegroups.com&lt;br /&gt;Subject: sent from test shell on Linux!&lt;br /&gt;&lt;br /&gt;Dude, gmail works in the test shell on Linux!&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;The team is still a long ways from even getting the web to render correctly, let alone building the real browser UI. But it's exciting to see things falling a little more into place each day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-5836155778829750383?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/5836155778829750383/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=5836155778829750383&amp;isPopup=true' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/5836155778829750383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/5836155778829750383'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2008/11/gmail-in-chromium-test-shell-on-linux.html' title='Gmail in Chromium &quot;Test Shell&quot; on Linux'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-3254502108604838233</id><published>2008-11-01T21:42:00.001-07:00</published><updated>2008-11-01T21:47:51.478-07:00</updated><title type='text'>New work blog</title><content type='html'>This is my new blog about work stuff. Cat pictures and vacation stories can be found over &lt;a href="http://blog.youngpup.net/"&gt;yonder&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-3254502108604838233?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/3254502108604838233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=3254502108604838233&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/3254502108604838233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/3254502108604838233'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2008/11/new-work-blog.html' title='New work blog'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-2740416688401136735</id><published>2008-11-01T20:26:00.000-07:00</published><updated>2008-11-01T21:41:47.307-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='greasemonkey'/><category scheme='http://www.blogger.com/atom/ns#' term='chromium'/><title type='text'>Greasemonkey in Chromium</title><content type='html'>Evan and I have been &lt;a href="http://codereview.chromium.org/8908"&gt;hacking on Greasemonkey&lt;/a&gt; support for Chromium in our 20% time. It's been fun. Actually, it was Evan who &lt;a href="http://codereview.chromium.org/6274"&gt;started&lt;/a&gt; the work... after months of pestering me, he got frustrated and started hacking.&lt;br /&gt;&lt;br /&gt;Implementation is more interesting than in Firefox because of Chromium's sandbox. The renderer processes are where scripts must be executed, but the renderers are not allowed to read the scripts from disk. So we set it up so that the privileged "browser" process reads the scripts into shared memory and broadcasts them to the renderers. It also watches for changes on disk and rebroadcasts when changes occur.&lt;br /&gt;&lt;br /&gt;Note that like everything else in Chromium nightlies, Greasemonkey support is considered experimental and may change, break, or disappear from build to build. That said, this is something a lot of us on Chromium are excited about, and look forward to continuing to improve.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-2740416688401136735?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/2740416688401136735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=2740416688401136735&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2740416688401136735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/2740416688401136735'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2008/11/greasemonkey-in-chromium.html' title='Greasemonkey in Chromium'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-352740419536688729</id><published>2007-07-12T10:53:00.000-07:00</published><updated>2007-07-12T11:25:38.407-07:00</updated><title type='text'>WorkerPool destruction cleanup done, now on to actual features</title><content type='html'>The main things that I have volunteered to do for the &lt;a href="http://code.google.com/p/google-gears/issues/list?can=2&amp;q=milestone%3AM1"&gt;next Gears milestone&lt;/a&gt; are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Implement &lt;a href="http://code.google.com/p/google-gears/issues/detail?id=33"&gt;better error-handling&lt;/a&gt; support for WorkerPools&lt;/li&gt;&lt;li&gt;Make the &lt;a href="http://code.google.com/p/google-gears/issues/detail?id=1"&gt;onmessage&lt;/a&gt; callback optional&lt;/li&gt;&lt;/ul&gt;I'm diving into the first of these two today. The first thing to do is figure out how to throw errors in each of the JavaScript engines globally. That is, if an error occurs in a WorkerPool and isn't handled by &lt;code&gt;WorkerPool.onerror&lt;/code&gt;, then the error should be thrown in the global context of the parent page. Basically, it should do the same thing as what happens when you run this JavaScript code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;window.setTimeout("throw new Error('boo!')", 100);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Spidermonkey (the JavaScript engine inside Firefox) has an API that I believe we can use for this purpose: &lt;a href="http://developer.mozilla.org/en/docs/JS_ReportError"&gt;JS_ReportError&lt;/a&gt;. I'm not sure if there is an equivalent for IE, or if I will have to basically do something like: &lt;code&gt;eval("throw new Error('boo!')")&lt;/code&gt;. I would like to avoid using eval if possible because it seems hacky and there are more security considerations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-352740419536688729?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/352740419536688729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=352740419536688729&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/352740419536688729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/352740419536688729'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2007/07/workerpool-destruction-cleanup-done-now.html' title='WorkerPool destruction cleanup done, now on to actual features'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2863235049034941132.post-1135167790934849778</id><published>2007-07-07T19:10:00.000-07:00</published><updated>2007-07-07T20:07:35.426-07:00</updated><title type='text'>Gearpad improvements for high-latency connections</title><content type='html'>I made some &lt;a href="http://groups.google.com/group/google-gears-eng/browse_thread/thread/b9cd46384f198501"&gt;changes&lt;/a&gt; to &lt;a href="http://aaronboodman.com/gearpad"&gt;Gearpad&lt;/a&gt; to make it work better on high-latency connections, like the one I use on my daily &lt;a href="http://googleblog.blogspot.com/2004/09/worth-drive.html"&gt;commute&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The problem was in my implementation of &lt;a href="http://en.wikipedia.org/wiki/Optimistic_concurrency_control"&gt;optimistic concurrency&lt;/a&gt;. This is what I used to store on the server for each note:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Id&lt;/li&gt;&lt;li&gt;Version&lt;/li&gt;&lt;li&gt;Content&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;At client startup, Gearpad fetches the current content and version of the note from the server. Then, when an edit occurs, it sends the version it has, plus the new content to the server. The server checks to see that the version sent matches the one that it has. If it does, it makes the edit, increments the version atomically, and returns the new content to the client. If the versions don't match, then a different client must have updated the note and this is a conflict. Right?&lt;br /&gt;&lt;br /&gt;Wrong. What happens if an edit occurs before a previous edit &lt;span style="font-style: italic;"&gt;from the same client&lt;/span&gt; returns? Here are a couple options:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Wait for the first edit to return, then send the second edit. This will make things much slower, and more complex since the editor state and server state start diverging more and more when the user is faster than the connection to the server.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Cancel the first edit and send the second one. This is what Gearpad does. But this means that sometimes the server gets the update and increments the version, but the new version doesn't make it back to the client. Then the second edit is sent and the server things a conflict has occurred.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Solution&lt;/span&gt;: the server needs to also store the last client that talked to it. It's only a conflict if the version is out of date *and* the update is from a new client. New server schema:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Id&lt;/li&gt;&lt;li&gt;Version&lt;/li&gt;&lt;li&gt;Content&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic; color: rgb(51, 51, 255);"&gt;LastClientId&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic; color: rgb(51, 51, 255);"&gt;NextClientId&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;&lt;/span&gt;&lt;/span&gt;This change also involved migrating Gears database schemas, which can be tricky. I'll talk about that next time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2863235049034941132-1135167790934849778?l=aaronboodman-com-v1.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronboodman-com-v1.blogspot.com/feeds/1135167790934849778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2863235049034941132&amp;postID=1135167790934849778&amp;isPopup=true' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/1135167790934849778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2863235049034941132/posts/default/1135167790934849778'/><link rel='alternate' type='text/html' href='http://aaronboodman-com-v1.blogspot.com/2007/07/gearpad-improvements-for-high-latency.html' title='Gearpad improvements for high-latency connections'/><author><name>boots</name><uri>http://www.blogger.com/profile/03885281513124696960</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://farm1.static.flickr.com/46/183719869_55f8ff0dfc.jpg?v=0'/></author><thr:total>5</thr:total></entry></feed>
