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

<channel>
	<title>Traceback (most recent call last): &#187; Firefox</title>
	<atom:link href="http://www.mikealrogers.com/archives/category/firefox/feed" rel="self" type="application/rss+xml" />
	<link>http://www.mikealrogers.com</link>
	<description></description>
	<lastBuildDate>Sat, 02 Jan 2010 21:30:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Moving on</title>
		<link>http://www.mikealrogers.com/archives/718</link>
		<comments>http://www.mikealrogers.com/archives/718#comments</comments>
		<pubDate>Sat, 02 Jan 2010 21:30:48 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windmill]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=718</guid>
		<description><![CDATA[The new year is bringing some big changes for me. A few weeks back I accepted a position at Relaxed Inc. and notified Mozilla that I would be leaving at the end of the year.
Mozilla
I started working at Mozilla 2 years ago. I started the day after my employment at the Open Source Applications Foundation [...]]]></description>
			<content:encoded><![CDATA[<p>The new year is bringing some big changes for me. A few weeks back I accepted a position at Relaxed Inc. and notified Mozilla that I would be leaving at the end of the year.</p>
<h2>Mozilla</h2>
<p>I started working at Mozilla 2 years ago. I started the day after my employment at the Open Source Applications Foundation ended. At this point I already took for granted some of the best parts of working at Mozilla; working for a public benefit organization, spending 100% of my time working on Open Source, working with very smart people in the open (lists, IRC, etc.).</p>
<p>But Mozilla is even more than all that. Succeeding at Mozilla means something more than a pat on the back and a good end of the year review. When you succeed at Mozilla you impact one of the most important products on the internet. You reach hundreds of millions of users and contribute to keeping the web an open and free (as in speech) world. There is no other place in the world you can work where you can conceivably have this kind of impact.</p>
<p>Mozilla as an organization is truly unique. Last year was the hardest I&#8217;ve ever had, i suffered a huge loss in my personal life and Mozilla was as supportive during this time as any of my friends or family. There are a lot of places that let you put so much of yourself in to the organization to help it attain it&#8217;s goals but there are only a handful that are there to support you when you need it.</p>
<h2>Relaxed Inc.</h2>
<p>I started using CouchDB in 2008 after a great talk by <a href="http://jan.prima.de/">Jan Lehnardt</a> at OSCON. I started using it right away and over the next year it re-shaped how I think about web development and applications. In the last 6 months my group at Mozilla has become a heavy CouchDB user and not just because of my own interest but because CouchDB was the only solution for some of the harder problems we needed to solve with our results storage.</p>
<p>As I&#8217;ve used CouchDB more and more and become a part of the CouchDB community I&#8217;ve had the pleasure of knowing some of the core contributors, three of which have decided to found a new startup around CouchDB; <a href="http://jan.prima.de/">Jan Lehnardt</a>, <a href="http://jchrisa.net">J Chris Anderson</a>, and the creator of CouchDB <a href="http://damienkatz.net/">Damien Katz</a>. Shorty after they received their funding they made an offer. It&#8217;s an amazing opportunity and while the decision to leave Mozilla is one of the hardest I&#8217;ve ever had to make I&#8217;m very excited about my future at Relaxed.</p>
<h2>The Future</h2>
<p>I&#8217;m really looking forward to working with everyone at Relaxed. It&#8217;s an exciting time and I&#8217;m not 100% sure yet which projects I currently work on that I will still have time to maintain. In the next week or so I&#8217;ll be doing a blog post on all the libraries I currently work on and maintain (it&#8217;s a <strong>long</strong> list) and what their status is moving forward. I still maintain code I wrote long before I worked at Mozilla and have every intention of continuing to work on some of the projects I started at Mozilla.</p>
<p>One thing is certain. I&#8217;m not the guy who figures out how to test the browser any more. Windmill and Mozmill are important projects that I have every intention of supporting by making time for code reviews and community support but I won&#8217;t be available to put time in to new feature work and refactoring like I have in the past. Luckily there are solid communities behind both of these projects and I&#8217;m confident that there are people who can continue to drive them in the future.</p>
<p>I don&#8217;t know what is going to happen next, all I know is that it should be fun, it won&#8217;t be like anything I&#8217;ve done before, and will certainly continue to include lots JavaScript and Python.</p>
<p>For everyone who depends on me and the code I&#8217;ve written over the last few years I&#8217;ll be sure to keep you all up to date. And one thing I can promise is that if you want to fix anything in one my projects, fork it on github and send me a pull request and I will always find time to look at it <img src='http://www.mikealrogers.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/718/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Hosting?</title>
		<link>http://www.mikealrogers.com/archives/713</link>
		<comments>http://www.mikealrogers.com/archives/713#comments</comments>
		<pubDate>Mon, 30 Nov 2009 00:56:22 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=713</guid>
		<description><![CDATA[I&#8217;m starting to work on a simple blog to replace this WordPress instance.
I&#8217;ve had a great run with WordPress but I have a few ideas I want to experiment with and I also want to dogfood couchdb-pythonviews a little more.
This blog is hosted on Dreamhost. Dreamhost has been a great host for a low impact [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m starting to work on a simple blog to replace this WordPress instance.</p>
<p>I&#8217;ve had a great run with WordPress but I have a few ideas I want to experiment with and I also want to dogfood <a href="http://github.com/mikeal/couchdb-pythonviews">couchdb-pythonviews</a> a little more.</p>
<p>This blog is hosted on Dreamhost. Dreamhost has been a great host for a low impact blog, the uptime hasn&#8217;t been 100% but all the maintenance has been easy and it&#8217;s also remained dirt cheap for the last few years.</p>
<p>I need to find a new hosting provider. I have one dedicated server but I don&#8217;t plan on running a blog there because that server is a little busy.</p>
<p>I need something cheap. I need root (or some kind of sudo jail) where I can run CouchDB and nginx and manage Python. Preferably Debian. Definitely Linux. Decent uptime.</p>
<p>I&#8217;ve considered EC2 but for a low impact site it&#8217;s actually quite expensive (~30 dollars a month before bandwidth) and the performance I&#8217;m told is about 5x slower than a Macbook.</p>
<p>Backups aren&#8217;t necessary since I have CouchDB replication for backing up all the important bits.</p>
<p>I&#8217;m open to any and all suggestions.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/713/feed</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>CouchDB View Performance (Python vs JavaScript)</title>
		<link>http://www.mikealrogers.com/archives/673</link>
		<comments>http://www.mikealrogers.com/archives/673#comments</comments>
		<pubDate>Thu, 05 Nov 2009 02:13:35 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=673</guid>
		<description><![CDATA[We&#8217;re gearing up for some heavy CouchDB usage in a new automation system and it has fallen upon me to do some performance benchmarking.
The most important thing for us to figure out was whether or not the CentOS virtual machine we&#8217;re currently running CouchDB on is going to be enough even in the short term. [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;re gearing up for some heavy CouchDB usage in a new automation system and it has fallen upon me to do some performance benchmarking.</p>
<p>The most important thing for us to figure out was whether or not the CentOS virtual machine we&#8217;re currently running CouchDB on is going to be enough even in the short term. Until today we&#8217;ve been running 0.9 and have encountered performance problems. </p>
<p>Our main bottleneck is, and has always been, view generation and update performance. We tend to have medium to large size documents (jobs are relatively small but results from test runs can be incredibly large). </p>
<p>View generation of large documents has typically been our biggest issue which we have previously mitigated by refreshing all views after any large write but that isn&#8217;t going to work for the amount of results that we plan on pouring in to the new system.</p>
<p>Last weekend I wrote a <a href="http://github.com/mikeal/couchdb-pythonviews">Python view server for CouchDB</a>. couchdb-python <a href="http://code.google.com/p/couchdb-python/source/browse/trunk/couchdb/view.py">includes a view server</a> but in the past I&#8217;ve heard complaints about performance (although none recently). In addition, the view server in couchdb-python only supports map and reduce, which is only about 1/5 of the current view server spec which includes handlers for update, show, list, filter, and validate which provide the groundwork for CouchDB as an application platform. As of Sunday my view server passes <a href="http://github.com/mikeal/couchdb/blob/master/test/query_server_spec.rb">all of the current CouchDB spec</a> and initial performance tests showed it faster than the JavaScript view server.</p>
<p>Below are the performance graphs for CouchDB trunk running on a CentOS virtual machine. I&#8217;m using Python 2.6 with the default stdlib json library. The spidermonkey core is 1.7 (I don&#8217;t know what the status of using 1.8 with CouchDB is but as we&#8217;ll see below, this won&#8217;t improve performance too much for these tests).</p>
<p>These graphs show view generation time for a given number of documents in a new database. The design doc I used had two views, one does emit(doc['type'],doc), the other emit(doc['_id'], 1). </p>
<p>The graphs support zooming, mouseover and all kinds of <a href="http://code.google.com/p/flot/">flot</a> goodness <img src='http://www.mikealrogers.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>JavaScript is the yellow line. Python is the Blue line.</p>
<p>
<script language="javascript" type="text/javascript" src="/js/flot/jquery.js"></script>
    <script language="javascript" type="text/javascript" src="/js/flot/jquery.flot.js"></script>
    <script language="javascript" type="text/javascript" src="/js/flot/jquery.flot.navigate.js"></script>
    <style>
    #placeholder .button {
        position: absolute;
        cursor: pointer;
    }
    .message {
        padding-left: 50px;
        font-size: smaller;
    }
    </style>
        <div id="placeholder" style="width:600px;height:300px"></div>
        <p id="message-text" class="message"></p><div id="message" class="message"></div>
        <p>This is a test of moderately sized documents, what we normally expect the size of a job or build description. Each document is identical and fairly simple with a size of ~1,588 bytes.</p>
        <div id="placeholder2" style="width:600px;height:300px"></div>
        <p id="message-text2" class="message"></p><div id="message2" class="message"></div>
        <p>These documents were incredibly large, they were taken from a full fennec mochitest run. Each document is identical and while large it consists mostly of small sized JSON objects inside a much larger JSON object coming in at ~139,096 bytes.</p>
    <script id="source" language="javascript" type="text/javascript">
    $(function () {
        var perf = {"medium_count_3000": {"python": 0.012593, "js": 0.019630000000000002}, "medium_count_9000": {"python": 0.012441000000000001, "js": 0.016513}, "large_gen_100": {"python": 4.8752870000000001, "js": 12.055866999999999}, "medium_gen_1000": {"python": 1.188747, "js": 1.8925399999999999}, "large_gen_10": {"python": 0.42780600000000002, "js": 1.540985}, "medium_count_100": {"python": 0.011244000000000001, "js": 0.013335}, "medium_count_1000": {"python": 0.010567, "js": 0.020129999999999999}, "medium_count_10": {"python": 0.011192000000000001, "js": 0.015753}, "large_count_100": {"python": 0.011394, "js": 0.022543000000000001}, "large_count_10": {"python": 0.0092929999999999992, "js": 0.013655}, "medium_gen_100": {"python": 0.132188, "js": 0.20717099999999999}, "large_gen_300": {"python": 14.486787, "js": 52.309240000000003}, "medium_count_6000": {"python": 0.011205, "js": 0.020074000000000002}, "large_count_300": {"python": 0.045109999999999997, "js": 0.060045000000000001}, "medium_gen_6000": {"python": 6.398968, "js": 11.531126}, "medium_gen_10": {"python": 0.53901500000000002, "js": 0.22401099999999999}, "medium_count_10000": {"python": 0.013492000000000001, "js": 0.020256}, "medium_gen_3000": {"python": 2.8234699999999999, "js": 5.5480289999999997}, "medium_gen_9000": {"python": 9.3583010000000009, "js": 16.559753000000001}, "medium_gen_10000": {"python": 10.365868000000001, "js": 17.842866000000001}};
        function sumf(f, t, m) {
                var res = 0;
                for (var i = 1; i < m; ++i) {
                    res += f(i * i * t) / (i * i);
                }
                return res;
            }
        var python_medium = [
                           [100,perf['medium_gen_100']['python']],
                           [1000,perf['medium_gen_1000']['python']],
                           [3000,perf['medium_gen_3000']['python']],
                           [6000,perf['medium_gen_6000']['python']],
                           [9000,perf['medium_gen_9000']['python']],
                           [10000,perf['medium_gen_10000']['python']],
                          ];
        var js_medium = [
                           [100,perf['medium_gen_100']['js']],
                           [1000,perf['medium_gen_1000']['js']],
                           [3000,perf['medium_gen_3000']['js']],
                           [6000,perf['medium_gen_6000']['js']],
                           [9000,perf['medium_gen_9000']['js']],
                           [10000,perf['medium_gen_10000']['js']],
                          ];
        var python_large = [
                           [10,perf['large_gen_10']['python']],
                           [100,perf['large_gen_100']['python']],
                           [300,perf['large_gen_300']['python']],
                          ];
        var js_large = [
                           [10,perf['large_gen_10']['js']],
                           [100,perf['large_gen_100']['js']],
                           [300,perf['large_gen_300']['js']],
                          ];                 
        var placeholder = $("#placeholder");
        var data = [
            { data: js_medium, color:"yellow"},
            {  data: python_medium, color:"blue"},
          ] 
        var options = {
          series: { lines: { show: true }, shadowSize: 0, points: { show: true } },
          xaxis: { zoomRange: [0.1, 10000], 
                   panRange: [-1, 10001],
                   ticks: [0,[100,"100Docs"],[1000,"1000Docs"],
                          [3000,"3000Docs"],[6000,"6000Docs"],[9000,"9000Docs"],
                          [10000,"10000Docs"], ],
                   },
          yaxis: { zoomRange: [0.1, 19], 
                   panRange: [-1, 20],
                   ticks: [[0,'.'],[1,"1s"],[3,"3s"],[5,"5s"],
                           [6,"6s"],[9,"9s"],[10,"10s"],[12,"12s"],[18,"18s"]
                           ],
                   min: -1,
                   max: 19
                  },
          zoom: {
              interactive: true
          },
          pan: {
              interactive: true
          },
          grid: { hoverable: true, clickable: true },
          }
          var plot = $.plot(placeholder, data, options);
          placeholder.bind('plotzoom', function (event, plot) {
              var axes = plot.getAxes();
              $("#message-text").html("Zooming to x: "  + axes.xaxis.min.toFixed(2)
                                 + " &ndash; " + axes.xaxis.max.toFixed(2)
                                 + " and y: " + axes.yaxis.min.toFixed(2)
                                 + " &ndash; " + axes.yaxis.max.toFixed(2));
          });
          function showTooltip(x, y, contents) {
              $('<div id="tooltip">' + contents + '</div>').css( {
                  position: 'absolute',
                  display: 'none',
                  top: y + 5,
                  left: x + 5,
                  border: '1px solid #fdd',
                  padding: '2px',
                  'background-color': '#fee',
                  opacity: 0.80
              }).appendTo("body").fadeIn(200);
          }
          var previousPoint = null;
          placeholder.bind("plothover", function (event, pos, item) {
              $("#x").text(pos.x.toFixed(2));
              $("#y").text(pos.y.toFixed(2));
                  if (item) {
                      if (previousPoint != item.datapoint) {
                          previousPoint = item.datapoint;
                          $("#tooltip").remove();
                          var x = item.datapoint[0].toFixed(2),
                              y = item.datapoint[1].toFixed(2);
                          showTooltip(item.pageX, item.pageY,y+'s');
                      }
                  }
                  else {
                      $("#tooltip").remove();
                      previousPoint = null;            
                  }
          });
      var placeholder2 = $("#placeholder2");
      var data2 = [
          { data: js_large, color:"yellow"},
          { data: python_large, color:"blue"},
        ]         
      var options2 = {
        series: { lines: { show: true }, shadowSize: 0, points: { show: true } },
        xaxis: { zoomRange: [0.1, 300], 
                 panRange: [-1, 301],
                 ticks: [0,[10,"10Docs"],[100,"100Docs"],[300,"300Docs"],], 
                 },
        yaxis: { zoomRange: [0.1, 60], 
                 panRange: [-1, 61],
                 ticks: [[0,'.'],[1,"1s"],[3,"3s"],[5,"5s"],[10,"10s"],[50,"50s"],[60,"60s"]],
                 min: -1,
                 max: 60
                },
        zoom: {
            interactive: true
        },
        pan: {
            interactive: true
        },
        grid: { hoverable: true, clickable: true },
        }
        var plot2 = $.plot(placeholder2, data2, options2);
        placeholder2.bind('plotzoom', function (event, plot2) {
            var axes = plot2.getAxes();
            $("#message-text2").html("Zooming to x: "  + axes.xaxis.min.toFixed(2)
                               + " &ndash; " + axes.xaxis.max.toFixed(2)
                               + " and y: " + axes.yaxis.min.toFixed(2)
                               + " &ndash; " + axes.yaxis.max.toFixed(2));
        });
        placeholder2.bind("plothover", function (event, pos, item) {
            $("#x").text(pos.x.toFixed(2));
            $("#y").text(pos.y.toFixed(2));
                if (item) {
                    if (previousPoint != item.datapoint) {
                        previousPoint = item.datapoint;
                        $("#tooltip").remove();
                        var x = item.datapoint[0].toFixed(2),
                            y = item.datapoint[1].toFixed(2);
                        showTooltip(item.pageX, item.pageY,y+'s');
                    }
                }
                else {
                    $("#tooltip").remove();
                    previousPoint = null;            
                }
        });
    });
  </script>
</p>
<p>I had also intended to chart the reduce performance with a simple sum operation but all the results were sub-second regardless of the amount of documents I threw at it with Python being only a little faster than JavaScript.</p>
<p>The nearly identical reduce time tells me that the actual code processing time inside the view functions are hardly different which means that the large difference in performance during view generation is most likely due to JSON serialization time. This also explains why larger documents cause an even greater difference in performance between Python and JavaScript.</p>
<h3>Improving Performance</h3>
<p>The Python view server is already as optimized as I can imagine for processing time inside the views. Since CouchDB doesn&#8217;t provide a way for the view server to support it&#8217;s own concurrency we&#8217;ve basically hit the wall here on what Python can provide. If we increased the complexity of the view functions I think that Python would start to show better than Spidermonkey 1.7, but 1.8 with traceing enabled would likely bridge that gap, possibly even showing JavaScript faster than Python.</p>
<p>The big problem is JSON serialization. We can make Python faster by compiling simplejson with C speedups. But using the C based JSON parser in newer versions of Spidermonkey requires some other changes to CouchDB since there are differences in the encoding of <strong>undefined</strong>.</p>
<p>At the end of the day though, this all looks great. CouchDB trunk (pre-0.11) is going to run fast enough for what we need right now even on a virtual machine and if we start to see view generation bottlenecks on views that aren&#8217;t hit as often and have to update a large number of documents we can just move those views to Python and the performance should be back down to sub-second.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/673/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Mutual Benefit</title>
		<link>http://www.mikealrogers.com/archives/651</link>
		<comments>http://www.mikealrogers.com/archives/651#comments</comments>
		<pubDate>Wed, 05 Aug 2009 20:55:32 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Economics]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Politics]]></category>
		<category><![CDATA[Social]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=651</guid>
		<description><![CDATA[I have started objecting to the description of a contributor as a &#8220;volunteer&#8221;. 
Volunteers are people who give their time/effort to an institution or group at some cost to them for little benefit in return. They usually do this as a labor of love, and therefor the argument can be made they receive some kind [...]]]></description>
			<content:encoded><![CDATA[<p>I have started objecting to the description of a contributor as a &#8220;volunteer&#8221;. </p>
<p>Volunteers are people who give their time/effort to an institution or group at some cost to them for little benefit in return. They usually do this as a labor of love, and therefor the argument can be made they receive some kind of emotional satisfaction from the exchange but it&#8217;s fundamentally categorized as a one way exchange where the volunteer is **giving** and the institution or group is **taking**.</p>
<p>Open source contributions are not market transactions. In a market there is a producer and a consumer, the transactions between them are to the benefit of either the producer or the consumer or both. Producer makes something, consumer evaluates the product and decides to give capital to the producer. Volunteer is a term used to describe an actor that is working for the benefit of the producer without reciprocal benefit to themselves to the extent that they benefit the producer.</p>
<p>Capital is the driving force in a market, it&#8217;s what enables the transactions. Workers are paid for contributions to product so that institutions can enable transactions where consumers are given a product in return for more capital. Capital is certainly a factor in open source, but it&#8217;s auxiliary. Capital may drive one side of the transaction, an actor paid to contribute to a product or consumption of a product used by the consumer to generate capital, but it does not drive each side of the transaction.</p>
<p>Contributors are not driven by a need to benefit a particular producer and are rarely driven by capital. In fact I can&#8217;t think of a way to describe open source contributions in terms of a market. In open source there is the **product**. The product exists almost as it&#8217;s own entity outside of the producers that created it or the consumers that use it. Because if it&#8217;s transparency and it&#8217;s ease of access and manipulation it cannot be viewed as a unit in a transaction within a market. Instead, all interactions need to be described in **relation to the product**. Contributors, institutions and individuals, that take part in production and those that take part in consumption take part in transactions with the **product**. This is an open source community, a group of actors taking part in transactions with a product.</p>
<p>The communities that thrive are the ones that remove barriers to these transactions and create tools that enable new transactions for more diverse contributions to the product. The transactions are not one-way, each transaction is two-way, benefiting both the product and the actor.</p>
<p>Rather than capital, mutual benefit seems to drive open source transactions. The product and the actor benefit from every transaction, with only a small portion of those transactions seeing capital as the benefit. The notion of a volunteer simply doesn&#8217;t exist in this model because there are rarely, if ever, transactions that only benefit a product at a cost to the actor. Actors **must** to be motivated and products are not &#8220;owned&#8221; in the traditional sense of ownership since their production is taken on by a community motivated by mutual benefit which tears down the relationship traditional market producers have with products.</p>
<p>Tools that are built to enable one sided transactions to a product usually fail because actors aren&#8217;t motivated by transactions that aren&#8217;t mutually beneficial.</p>
<p>A quick look at Firefox shows a very broad and diverse number of tools that enable mutually beneficial transactions. Although we often think about the new kinds of contributions that additions to Firefox itself will enable like [Personas](http://www.getpersonas.com/) or [Jetpack](https://jetpack.mozillalabs.com/) we also have a variety of tools that enable non-code contributions. Everything from that little button that reports a crash (benefits the product&#8217;s stability and improves your browser experience) to [SUMO](http://support.mozilla.com/en-US/kb/) (users seek resolution to support issues while providing the product with immeasurable usage feedback and bugs) are examples of tools that enable new transactions with the product that are mutually beneficial to the product and the actor.</p>
<p>One of my favorite things about working at Mozilla is being able to think about new kinds of contributions and how to enable them. There are few products with such a large and diverse ecosystem of users so the opportunities for new contribution is uniquely large so long as we create tools that are mutually beneficial.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/651/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Dead Font Walkin&#8217;</title>
		<link>http://www.mikealrogers.com/archives/640</link>
		<comments>http://www.mikealrogers.com/archives/640#comments</comments>
		<pubDate>Mon, 20 Jul 2009 21:44:57 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Rant]]></category>
		<category><![CDATA[Social]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=640</guid>
		<description><![CDATA[I&#8217;m about to go on a tear so it&#8217;s worth saying that all of what I&#8217;m writing are my own opinions and in no way whatsoever reflect the opinions or policies of my employer.
Any new technology can have a side effect of making an entire industry irrelevant. Every time an industry is on the brink [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m about to go on a tear so it&#8217;s worth saying that all of what I&#8217;m writing are my own opinions and in no way whatsoever reflect the opinions or policies of my employer.</p>
<p>Any new technology can have a side effect of making an entire industry irrelevant. Every time an industry is on the brink they try to plead for their own survival. Their tone and message is predictable, &#8220;you&#8217;ll miss our profession when it&#8217;s gone&#8221;. But of course, the profession never disappears only the institutions that used to enable it which are no longer relevant. These Institutions cannot survive in a new world so they scream to save their business model and claim that their profession is what is at risk.</p>
<p>I love journalism, and music, and I&#8217;m a total font geek but I just can&#8217;t stand newspapers, record labels, and these god forsaken font ["foundries"](http://blog.mozilla.com/rob-sayre/2009/07/19/broken-record/).</p>
<p>Let me get this straight. Your business model is to create fonts, **once**, and then license them on a per-use basis. I can&#8217;t be the first one to tell you **THAT ISN&#8217;T GONNA FUCKING WORK ANYMORE**.</p>
<p>@font-face has the side effect of invalidating your whole business model by driving demand for ubiquitous free and open fonts. I&#8217;m sorry. I wish it didn&#8217;t have to be this way. The world is cruel, and you&#8217;re fucked. </p>
<p>Print publications bought your fonts because they had fairly high production costs already and adding a little on top wasn&#8217;t going to break them. But this is the web, content is ubiquitous and free so the tools to create it have to be ubiquitous and free as well. </p>
<p>To steal a little from [Clay Shirky](http://www.shirky.com/), your industry is now going to suffer from mass-amatuerization. Font creation will not die with the foundries, there is going to be more font creation than there ever has been in human history, it&#8217;s just going to be open and free. The cost of producing a font is nearly zero. There is labor involved but the tools are ubiquitous and mostly free while distribution is a non-issue. Now that **anyone** can create a font and quality is determined solely by the creators talent, and we can actually **use** open fonts in the web content we create, it is safe to expect an explosion in the creation of fonts.</p>
<p>There is no technology that can save your business model because it pre-dates the web. The web changed the world you live in and you don&#8217;t get to change it back. If you don&#8217;t believe me you should have a chat with some former stock photographers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/640/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Duke Nukem OS</title>
		<link>http://www.mikealrogers.com/archives/628</link>
		<comments>http://www.mikealrogers.com/archives/628#comments</comments>
		<pubDate>Wed, 15 Jul 2009 17:55:58 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Parody]]></category>
		<category><![CDATA[Social]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=628</guid>
		<description><![CDATA[We have a lot of great operating systems out there but they were all created before the web and high performance 3D gaming. To try and move technology forward I am announcing the Duke Nukem Operating System.
Duke Nukem OS is a lightweight high performance open source operating system. The first release, codename &#8220;Forever&#8221;, is due [...]]]></description>
			<content:encoded><![CDATA[<p>We have a lot of great operating systems out there but they were all created before the web and high performance 3D gaming. To try and move technology forward I am announcing the Duke Nukem Operating System.</p>
<p>Duke Nukem OS is a lightweight high performance open source operating system. The first release, codename &#8220;Forever&#8221;, is due out in late 2010. A promotional comic book will accompany the release and to insure it is available by the delivery date I plan to hire [Kevin Smith](http://en.wikipedia.org/wiki/Kevin_Smith) and [Alex Ross](http://en.wikipedia.org/wiki/Alex_Ross) to write and illustrate it.</p>
<p>Although no screenshots, specifications, or source code will be available until release consider this a call to action for the open source community to get involved in the project.</p>
<p>This new operating system will be built on the Linux kernel but I will be throwing out the bloated window managers Linux is currently known for and building a next generating interface. I&#8217;ll be using XULRunner, the Mozilla runtime used to create Firefox, as the basis for this window manager but the tools to develop applications are exclusively web3.0 &#8220;semantic web&#8221; standards. [RDFa](http://www.w3.org/TR/xhtml-rdfa-primer/), a next generation semantic markup language known for it&#8217;s simplicity and rapid rate of adoption, will be the primary language for building in this next generation operating system.</p>
<p>More updates in the future.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/628/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Up for a Pint?</title>
		<link>http://www.mikealrogers.com/archives/622</link>
		<comments>http://www.mikealrogers.com/archives/622#comments</comments>
		<pubDate>Thu, 02 Jul 2009 13:55:51 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Windmill]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=622</guid>
		<description><![CDATA[I&#8217;m in London for the next few days and would love to grab a drink with any community members be you Mozilla, CouchDB, Python, Windmill, JavaScript or just plain old coffee, whisky or beer geeks  
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m in London for the next few days and would love to grab a drink with any community members be you Mozilla, CouchDB, Python, Windmill, JavaScript or just plain old coffee, whisky or beer geeks <img src='http://www.mikealrogers.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/622/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Conference Season Begins</title>
		<link>http://www.mikealrogers.com/archives/613</link>
		<comments>http://www.mikealrogers.com/archives/613#comments</comments>
		<pubDate>Tue, 16 Jun 2009 01:07:37 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Windmill]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=613</guid>
		<description><![CDATA[I&#8217;ll be leaving tomorrow morning for [Open Source Bridge](http://opensourcebridge.org/) in Portland, Oregon.
I&#8217;m putting together a new [Windmill talk](http://opensourcebridge.org/sessions/36) that tries to incorporate all the feedback we&#8217;ve received over the last year of speaking which I&#8217;ll be presenting on Thursday.
Mozilla is also a [sponsoring](http://opensourcebridge.org/sponsors/) the conference and there is going to be some great [Firefox related [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ll be leaving tomorrow morning for [Open Source Bridge](http://opensourcebridge.org/) in Portland, Oregon.</p>
<p>I&#8217;m putting together a new [Windmill talk](http://opensourcebridge.org/sessions/36) that tries to incorporate all the feedback we&#8217;ve received over the last year of speaking which I&#8217;ll be presenting on Thursday.</p>
<p>Mozilla is also a [sponsoring](http://opensourcebridge.org/sponsors/) the conference and there is going to be some great [Firefox related sprints in the hacker lounge](http://opensourcebridge.org/wiki/Hacker_Lounge). Dietrich is also giving what sounds like an awesome talk on extending Firefox called [Firefox Switchblade](http://opensourcebridge.org/sessions/251).</p>
<p>Hope to see you all there!</p>
<p>PS. I&#8217;ll also be at EuroPython and the Community Leadership Summit, more on those later <img src='http://www.mikealrogers.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/613/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RiP: Annotations Remix</title>
		<link>http://www.mikealrogers.com/archives/609</link>
		<comments>http://www.mikealrogers.com/archives/609#comments</comments>
		<pubDate>Wed, 13 May 2009 23:25:34 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=609</guid>
		<description><![CDATA[I had some fun this weekend with Python, &#60;video&#62;, CouchDB and Brett Gaylor&#8217;s [RiP: A Remix Manifesto](http://www.ripremix.com). In just a few hours I was able to crank out a little [annotations remix](http://ripannotations.pythonesque.org) which allows anyone to add annotations to the film that are displayed as people view it.
I&#8217;m hosting it on my little mac mini [...]]]></description>
			<content:encoded><![CDATA[<p>I had some fun this weekend with Python, &lt;video&gt;, CouchDB and Brett Gaylor&#8217;s [RiP: A Remix Manifesto](http://www.ripremix.com). In just a few hours I was able to crank out a little [annotations remix](http://ripannotations.pythonesque.org) which allows anyone to add annotations to the film that are displayed as people view it.</p>
<p>I&#8217;m hosting it on my little mac mini (currently hidden in a data-center) so hopefully it doesn&#8217;t fall over pushing so much video <img src='http://www.mikealrogers.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>I&#8217;ve posted all the code up on [github](http://github.com/mikeal/ripannotations/tree/master). The more I use &lt;video&gt; and CouchDB the more excited I get about the future of web applications. This entire project was done in little chunks of spare time over the weekend and most of that was me messing around with styling. To get the data stored, queried, and displayed took less than 2 hours.</p>
<p>Hope you all enjoy the annotations remix and if you haven&#8217;t already go and pay what you want for a terrific copy of [RiP: A Remix Manifesto](http://www.ripremix.com). It&#8217;s worth it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/609/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Professionals or People</title>
		<link>http://www.mikealrogers.com/archives/601</link>
		<comments>http://www.mikealrogers.com/archives/601#comments</comments>
		<pubDate>Wed, 29 Apr 2009 17:57:02 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Social]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=601</guid>
		<description><![CDATA[The Rails community seems to be on the verge of imploding, not necessarily because of a [particular event](http://www.ultrasaurus.com/sarahblog/2009/04/gender-and-sex-at-gogaruco/) but because of the [response by Rails leadership](http://afreshcup.com/2009/04/28/a-painful-decision/) to the event and their lack of meaningful reflection on why this happened.
This event has been well commented on, so I won&#8217;t go in to all the details, but [...]]]></description>
			<content:encoded><![CDATA[<p>The Rails community seems to be on the verge of imploding, not necessarily because of a [particular event](http://www.ultrasaurus.com/sarahblog/2009/04/gender-and-sex-at-gogaruco/) but because of the [response by Rails leadership](http://afreshcup.com/2009/04/28/a-painful-decision/) to the event and their lack of meaningful reflection on why this happened.</p>
<p>This event has been well commented on, so I won&#8217;t go in to all the details, but unsurprisingly the best comments I&#8217;ve read so far have come from women, in particular [Audrey Eschright](http://dyepot-teapot.com/2009/04/25/dear-fellow-rubyists/). It&#8217;s good to see meaningful discussion in that community but I think the proposed solution of increased &#8220;professionalism&#8221; is counterproductive and generating an even more hostile response from [Rails leadership](http://loudthinking.com/posts/39-im-an-r-rated-individual).</p>
<p>Professionalism doesn&#8217;t have a good history of promoting equality. After segregation &#8220;professional&#8221; was one of many code words for &#8220;white male&#8221; and even after many years when non-white males began entering the work force the idea of professionalism served to strip people of their culture and identity to better fit in to a white male dominated environment. For those of us in open source, and especially those who have left traditional corporations, we identify &#8220;professionalism&#8221; as the way corporations turn people in to plastic dolls in suites that can talk to other plastic dolls from other corporations at trade shows without getting &#8220;off message&#8221;. Luckily, we aren&#8217;t talking about a corporation here, we&#8217;re talking about a community and community isn&#8217;t about professionals it&#8217;s about people.</p>
<p>I think people see professionalism as a solution to this problem because it provides a way for us to change people&#8217;s conduct that we disagree with without actually changing people or how they think they should conduct themselves in a community. The real problem here is that some  **people** think it&#8217;s just fine to engage in public conduct that knowingly excludes people and doesn&#8217;t help include or encourage any new participation. </p>
<p>When news of this little outburst broke I have to say I wasn&#8217;t surprised that it happened in the Rails community. All tech communities have a low number of female participants, this is something nobody is great at yet, but for some time now Rails has been the worst offender. In the early days Rails was promoted by DHH in what, at the time, sounded like a great strategy: Attack dominant technologies (Java) and piss people off that use them long enough to check out your stuff. This strategy generated huge buzz and lead to one of the fastest adoptions of a new technology I&#8217;ve ever seen and it&#8217;s worth noting that the technology was actually so good that people could go from being a pissed off Java developer to a Rails developer in a relatively short amount of time.</p>
<p>But the biggest problem with DHH&#8217;s strategy was that it was hostile and it intentionally excluded a large number of people who were invested in the old technology and couldn&#8217;t get over being pissed off at DHH. The first thing DHH will say is &#8220;well, we don&#8217;t want or care about those people&#8221;, and he&#8217;s right, Rails doesn&#8217;t need those people. But when you, as the leader of a project, are hostile and partake in action that **intentionally excludes people**, regardless of who those people are, it creates an environment where others see no need to alter their behavior not to exclude people. </p>
<p>I&#8217;m really disheartened by [DHH's "I'm an R rated individual" post](http://www.loudthinking.com/posts/39-im-an-r-rated-individual), because it&#8217;s not that he&#8217;s wrong, he&#8217;s actually right, he should be able to be an individual in the community he&#8217;s built, but if he doesn&#8217;t intentionally curb some of his behavior he&#8217;s going to encourage exaggerations of the worst parts of his personality by the example he sets. It&#8217;s great that DHH loves Louis C.K and his dick jokes, but that doesn&#8217;t mean he would intentionally start a keynote with them, he knows better, and that&#8217;s what makes the difference and that&#8217;s what is so wrong with Matt&#8217;s talk, he knew before he went up there that this would make a lot of people uncomfortable and discourage participation from women and he did it anyway.</p>
<p>In order to lead an inclusive community you have to encourage participation and allow everyone to be individuals. If you treat everyone with respect, no matter who they are and no matter what they do, others will conduct themselves the same way. It&#8217;s always easier to respond to hostility with hostility but all you&#8217;re doing is creating an environment where hostility is the norm and it&#8217;s alright to exclude people.</p>
<p>The kind of communities we want are not impossible, in fact we get closer and closer every day. I&#8217;m lucky enough to be at [#moz09](http://search.twitter.com/search?q=%23moz09) this week, and I&#8217;m looking around at over 200 people from different cultures from around the world none of which seem to be trying to hide who they are or where they came from for some notion of &#8220;professionalism&#8221; and everyone treats each other with respect and every day we gather more participation from a broader set of individuals. We aren&#8217;t perfect, we&#8217;re never where we want to be, but we should be confident we&#8217;re going in the right direction.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/601/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>&lt;video&gt; just feels good</title>
		<link>http://www.mikealrogers.com/archives/575</link>
		<comments>http://www.mikealrogers.com/archives/575#comments</comments>
		<pubDate>Tue, 28 Apr 2009 18:29:59 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=575</guid>
		<description><![CDATA[I&#8217;ve been writing some automated tests for the new &#60;video&#62; work in Firefox 3.5 and it&#8217;s been incredibly fun. I spent some time in the trenches at Real Networks and dealt with accessing embedded video in the browser so I really appreciate how much nicer &#60;video&#62; is than embedded players like Real and Flash.
People talk [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been writing some automated tests for the new &lt;video&gt; work in Firefox 3.5 and it&#8217;s been incredibly fun. I spent some time in the trenches at Real Networks and dealt with accessing embedded video in the browser so I really appreciate how much nicer &lt;video&gt; is than embedded players like Real and Flash.</p>
<p>People talk a lot about embedded plugins being *&#8221;stuck in a box&#8221;* and while this is partially true I don&#8217;t think it&#8217;s descriptive enough. Embedded players like RealPlayer and Flash open up methods that can be called from javascript, so you do have some ways of interacting with the box, but it&#8217;s limited to somewhat rigid pre-defined interfaces. It&#8217;s also worth noting that using these interfaces just doesn&#8217;t **feel** like web development the way doing regular JavaScript and DOM feels. It&#8217;s not dynamic and you&#8217;re limited to only doing **what the plugin authors have already thought of**. The beautiful thing about the browser as a platform is that it enables usage far beyond what the original creators have intended.</p>
<p>Using &lt;video&gt; **feels** like the web. You resize it by setting size attributes the same way you would an interface node. You seek by setting the currentTime attribute, you can listen for the time changes to create your own interface by adding a listener for &#8220;timeupdate&#8221; events. You can write interfaces around &lt;video&gt; without switching contexts because it&#8217;s not a foreign technology jammed in to the browser. Here is some javascript that implements a few video controls.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> v <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;v1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;playDiv&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">onclick</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>v.<span style="color: #660066;">play</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span>
document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;pauseDiv&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">onclick</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>v.<span style="color: #660066;">pause</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span>
document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;reloadDiv&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">onclick</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>v.<span style="color: #660066;">load</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span>
document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;seekDiv&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">onclick</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    v.<span style="color: #660066;">currentTime</span> <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'seekField'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">value</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Isn&#8217;t that beautiful! Maybe I&#8217;m overly excited because I&#8217;ve had to deal with this using older technologies but this just **feels** good, and if it feels good then I know people are going to get excited about it and build cool stuff.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/575/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Can&#8217;t blame the user? Blame the user community!</title>
		<link>http://www.mikealrogers.com/archives/577</link>
		<comments>http://www.mikealrogers.com/archives/577#comments</comments>
		<pubDate>Thu, 23 Apr 2009 20:10:28 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Social]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=577</guid>
		<description><![CDATA[I&#8217;ve started stewing over [Garrett Murray](http://log.maniacalrage.net/)&#8217;s post on [negative user reviews for his Ego application](http://log.maniacalrage.net/post/98510137/a-little-over-a-week-and-a-half-ago-google) for iPhone that recently showed some breakage when Google Analytics changed up. What started to really upset me was one of his closing paragraphs.

This kind of thing continually reinforces something I’ve thought about a lot since the App store was [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve started stewing over [Garrett Murray](http://log.maniacalrage.net/)&#8217;s post on [negative user reviews for his Ego application](http://log.maniacalrage.net/post/98510137/a-little-over-a-week-and-a-half-ago-google) for iPhone that recently showed some breakage when Google Analytics changed up. What started to really upset me was one of his closing paragraphs.</p>
<blockquote><p>
This kind of thing continually reinforces something I’ve thought about a lot since the App store was released, which sounds horrible to say but it might be true: Apple is creating an ecosystem of the kind of customers I don’t want. With the ridiculous approval process leaving bugfixes to take over a week to show up, with prices being driven down to nothing by farting apps… it just feels hostile to me. While I have plenty of great customers who have been raving about the app, all it takes is one little issue and it all comes crashing down.
</p>
</blockquote>
<p>It&#8217;s no longer acceptable for consumer applications to &#8220;blame the user&#8221;. Sure, many people still do it, but if a blog post like this just blamed individual users for their complaints without this closing paragraph it wouldn&#8217;t be gaining so much steam and I probably never would have read about it. Instead Garrett blames the *community* of users, and by extension Apple for process that encourages this kind of community.</p>
<p>The first rule of community leadership in open source is simple; **&#8221;Don&#8217;t be an asshole.&#8221;**. While simple, sometimes it&#8217;s the hardest rule to follow. Many people in the community can be difficult, some of them downright hostile, but you can&#8217;t be hostile back and you can&#8217;t be an asshole. When you&#8217;re hostile or an asshole in your community you give license to the community to do the same. You cultivate the behavior that antagonized you in the first place. This is the rule when trying to lead contributors and I have to assume it&#8217;s the rule when trying to lead users and posts like this violate the rule by blaming users for their own expectations and then dismissing them altogether.</p>
<p>He tries to deflect attention to Apple since they are the gate keeper. Dismissing the bulk of your user community due to the gate keeper is logic that is so convenient you know it has to be flawed. The truth is **most** platforms have some kind of gate keeper, this is the world that we live in, but your complaints about your users have nothing to do with Apple.</p>
<p>iFart is 1 dollar but you&#8217;re giving it way too much credit if you think that&#8217;s why iPhone users have lower price expectations. You know what else is 1 dollar, Ocarina. Applications and games like Ocarina are larger triumphs of creativity than they are of engineering time. Not to say they are easy, or simple, but they are priced cheaply because the creators are confident in their product and because they didn&#8217;t spend a year developing it. This is where iPhone users have cultivated their expectations about interface, graceful failure, and low prices, because of your competitors not because of the gate keeper.</p>
<p>But even if all the user community&#8217;s expectations and demeanor is Apple&#8217;s fault, even if your users are cheap and vicious and given way too big a soap box, it&#8217;s still your fault. </p>
<p>As an example. Firefox get&#8217;s requests for features from Windows users to make certain things be &#8220;more like Windows&#8221;. If you look at the Firefox interface over 3 operating systems you&#8217;ll notice that the preferences menu item moves around based on which platform it&#8217;s on. The truth is, if you designed an interface from the ground up in some ideal world there would be one place that is best to put the preferences item, but that&#8217;s not the world we live in, we live in a world of expectations from user communities. The easiest thing to do is to say &#8220;we don&#8217;t need those users&#8221; or &#8220;those users are stupid and don&#8217;t understand proper design&#8221; but it&#8217;s not the **right** thing to do because it&#8217;s not what **they** want.</p>
<p>What your users are really saying with those complaints is that this failure frustrated them to the point of opening up iTunes and writing a complaint, not just that something broke. You could have failed more gracefully, you could have presented them with a button that opened a support web page with more detailed information and assurances that it was being resolved. Then after some time the bad reviews would get swallowed up by the positive ones you mentioned. But now you don&#8217;t have to do anything because you&#8217;ve convinced yourself that you did nothing wrong and it&#8217;s just a bunch of users you don&#8217;t want complaining about something they are too dumb to understand.</p>
<p>I hope some day Garrett finds his perfect user community with expectations that match his own. I&#8217;ll stick to working on products for everyone else, listen to their feedback seriously and try to improve them.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/577/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Windmill 1.1 (the PyCon release)</title>
		<link>http://www.mikealrogers.com/archives/555</link>
		<comments>http://www.mikealrogers.com/archives/555#comments</comments>
		<pubDate>Wed, 08 Apr 2009 01:34:09 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Windmill]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=555</guid>
		<description><![CDATA[So much good stuff landed in Windmill over the last few weeks that we decided to push another major release.
The biggest new features are:
* [django management command](http://trac.getwindmill.com/wiki/WindmillAndDjango) for running windmill tests ([Jacob](http://jacobian.org/) said the existing django support wasn&#8217;t good enough and I agreed so I wrote this during the PyCon Sprints)
* new [nose plugin](http://trac.getwindmill.com/wiki/BookChapter-5-RunningTests#RunningTestsfromNose)
* cygwin [...]]]></description>
			<content:encoded><![CDATA[<p>So much good stuff landed in Windmill over the last few weeks that we decided to push another major release.</p>
<p>The biggest new features are:</p>
<p>* [django management command](http://trac.getwindmill.com/wiki/WindmillAndDjango) for running windmill tests ([Jacob](http://jacobian.org/) said the existing django support wasn&#8217;t good enough and I agreed so I wrote this during the PyCon Sprints)<br />
* new [nose plugin](http://trac.getwindmill.com/wiki/BookChapter-5-RunningTests#RunningTestsfromNose)<br />
* cygwin support contributed by [Simon Law](http://sfllaw.livejournal.com/) (he went and wrote an implemenation of [winreg for cygwin](http://pypi.python.org/pypi/cygwinreg) to get this to work).</p>
<p>There were also some really good bug fixes that landed:</p>
<p>* much better unicode handling and serialization (adam)<br />
* fix for POST to foreign domains ([Anthony Lenton](http://anthony.lenton.com.ar))<br />
* continued improvements to click simulation (adam)</p>
<p>The release is [up on PyPI](http://cheeseshop.python.org/pypi/windmill) and you can install/update with:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">$ easy_install -U windmill</pre></div></div>

<p>For anyone interesting in working **on** windmill we&#8217;re having a Sprint in #windmill on irc.freenode.net tomorrow April 8th, 2008 for pretty much all day. We&#8217;re going to be improving the unittests for Windmill itself.</p>
<p>The next planned major release will be 1.2 which will include the much anticipated SSL support, courtesy of some great work being done by Anthony.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/555/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Windmill 1.0!</title>
		<link>http://www.mikealrogers.com/archives/521</link>
		<comments>http://www.mikealrogers.com/archives/521#comments</comments>
		<pubDate>Thu, 26 Mar 2009 04:36:11 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Windmill]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=521</guid>
		<description><![CDATA[Just in time for PyCon we&#8217;re releasing [Windmill 1.0](http://www.getwindmill.com/archives/412). It&#8217;s been almost 3 years of development and I&#8217;m both excited and relieved to have something we&#8217;re comfortable calling 1.0.
The latest RCs have seen bigger improvements than we thought would make it. A new wave of contributions has given us some great new features in Django [...]]]></description>
			<content:encoded><![CDATA[<p>Just in time for PyCon we&#8217;re releasing [Windmill 1.0](http://www.getwindmill.com/archives/412). It&#8217;s been almost 3 years of development and I&#8217;m both excited and relieved to have something we&#8217;re comfortable calling 1.0.</p>
<p>The latest RCs have seen bigger improvements than we thought would make it. A new wave of contributions has given us some great new features in Django support and test serialization and [Adam](http://www.adamchristian.com) has done some great UI work as well.</p>
<p>Big thanks to everyone who contributed to the release and I hope to see many of you at PyCon. Adam is doing a [talk on windmill](http://us.pycon.org/2009/conference/schedule/event/9/) which I&#8217;ll be helping out with and Adam and I will also be on a [functional testing tools panel](http://us.pycon.org/2009/conference/schedule/event/88/) which should be a lot of fun. And if you&#8217;re staying around for the sprint days of the conference we&#8217;ll be leading a [windmill sprint](http://us.pycon.org/2009/sprints/projects/windmill/).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/521/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Multiple feed rels are a bad idea</title>
		<link>http://www.mikealrogers.com/archives/490</link>
		<comments>http://www.mikealrogers.com/archives/490#comments</comments>
		<pubDate>Thu, 12 Mar 2009 19:00:47 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=490</guid>
		<description><![CDATA[You don&#8217;t have to be a geek to suffer from information overload these days. Average users are hammered with too much data from too many sources and are seeking new ways to automate some of their manual workflows and creating their own contextual filters to help then deal with an overwhelming flood of information.
Feeds are [...]]]></description>
			<content:encoded><![CDATA[<p>You don&#8217;t have to be a geek to suffer from information overload these days. Average users are hammered with too much data from too many sources and are seeking new ways to automate some of their manual workflows and creating their own contextual filters to help then deal with an overwhelming flood of information.</p>
<p>Feeds are an obvious and helpful tool in helping *normal* people automate the tasks of keeping up with information streams. Many users are finding ways to use feeds to **follow** a particular site or person and using new tools and services that work better for them than the traditional big RSS Readers. Personally, I think Firefox3 has the best workflows for integrating with any of these tools. Let&#8217;s work through the subscribe workflow for my blog.</p>
<p><img src="http://www.mikealrogers.com/wp-content/uploads/2009/03/picture-11.png" alt="picture-11" title="Feed Button Close In" width="198" height="145" class="aligncenter size-full wp-image-492" /></p>
<p>* Click on the feed button.</p>
<p><img src="http://www.mikealrogers.com/wp-content/uploads/2009/03/picture-2.png" alt="Subscribe Page" title="Subscribe Page" width="461" height="245" class="aligncenter size-full wp-image-493" /></p>
<p>* Select or configure your client and click subscribe.</p>
<p>This is a very simple workflow and it makes web based tools first class citizens where previous versions of Firefox and other browsers only support desktop client subscriptions. You don&#8217;t need to make a lot of decisions or know anything about the feed technology or protocols behind the scenes.</p>
<p>But the workflow for my blog is an ideal scenario where only one rel=&#8221;alternate&#8221; feed has been parsed from the page. This workflow becomes more complicated when multiple rel=&#8221;alternate&#8221; links are in the page.</p>
<p><img src="http://www.mikealrogers.com/wp-content/uploads/2009/03/picture-3.png" alt="picture-3" title="picture-3" width="428" height="149" class="aligncenter size-full wp-image-494" /></p>
<p>Is this really necessary? 90% of the people who click this want to follow new posts and nothing else. More importantly what feed would **you** like people to subscribe to? You can make a decision here to push people in the direction you would like and somewhere else on the page you can offer them these more complicated options if they are seeking out alternate subscriptions.</p>
<p><img src="http://www.mikealrogers.com/wp-content/uploads/2009/03/picture-4.png" alt="picture-4" title="picture-4" width="294" height="103" class="aligncenter size-full wp-image-495" /></p>
<p>This is terrible. You&#8217;re basically undercutting all the work browser vendors have done to let users start to integrate feeds in to their workflows without understanding feed protocols.</p>
<p>If we want to encourage adoption of these technologies we have to help eliminate this kind of extra confusion from basic user workflows. Feeds aren&#8217;t just being used in traditionally feed readers now, those readers de-contextualize the information so that power users can burn through information quicker. New tools are enabling users to use feeds to &#8220;follow&#8221; a site, they way they might follow someone on twitter. These unnecessary subscription options discourage that kind of adoption because it presents choices that fall outside of the bounds of that workflow.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/490/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>MozMill 1.1 Released</title>
		<link>http://www.mikealrogers.com/archives/471</link>
		<comments>http://www.mikealrogers.com/archives/471#comments</comments>
		<pubDate>Thu, 05 Mar 2009 23:51:50 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=471</guid>
		<description><![CDATA[Today we finished up a much anticipated MozMill 1.1 release.
The UI has been totally re-worked by Adam based mainly of design session feedback. We ditched the old xul UI and are just using html loaded via chrome url, this made development an order of magnitude easier and allowed us to use a great syntax highlighting [...]]]></description>
			<content:encoded><![CDATA[<p>Today we finished up a much anticipated MozMill 1.1 release.</p>
<p>The UI has been totally re-worked by <a href="http://www.adamchristian.com">Adam</a> based mainly of design session feedback. We ditched the old xul UI and are just using html loaded via chrome url, this made development an order of magnitude easier and allowed us to use a great syntax highlighting library for the editor that we could never quite get working in xul. </p>
<p>The release also has lots of new features like automatically binding the mozmill window to the side of a test window and editing of multiple tests at once. A whole slew of bugfixes made it in, mostly logged by <a href="http://www.hskupin.info/">Henrik</a>, including fixes to mulit-window recording. </p>
<p>At the suggestion of <a href="http://weblogs.mozillazine.org/dmose/">Dan Mosedale</a> we also added new asynchronous test support for more unittesting capabilities. Documentation is still on it&#8217;s way but you can refer to the <a href="http://code.google.com/p/mozmill/source/browse/trunk/test/test_unit.js">mozmill unittest</a> for now.</p>
<p>MozMill can be downloaded a few ways, the extension is available on <a href="http://mozmill.googlecode.com/files/mozmill-1.1.xpi">google code downloads</a> or the Python package can be installed via <a href="http://pypi.python.org/pypi/mozmill">PyPI</a></p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">$ easy_install -U mozmill</pre></div></div>

<p><a href="http://cmtalbert.wordpress.com/">Clint</a> also just finished up a big round of new <a href="http://quality.mozilla.org/mozmill-docs">end user docs and API documentation cleanup and reformatting on QMO.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/471/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Introducing&#8230; PushMarks</title>
		<link>http://www.mikealrogers.com/archives/433</link>
		<comments>http://www.mikealrogers.com/archives/433#comments</comments>
		<pubDate>Thu, 19 Feb 2009 06:31:42 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=433</guid>
		<description><![CDATA[
I used to be really in to public bookmark services like delicious and magnolia. Then Firefox3 was released and the new bookmarks UI combined with the awesomebar was just much easier to use than any of the sharing extensions.
I never took the time to sit down and write a simple sync/push extension because I just figured [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-434 alignright" title="pushmarks" src="http://www.mikealrogers.com/wp-content/uploads/2009/02/pushmarks.png" alt="pushmarks" width="76" height="72" /></p>
<p>I used to be really in to public bookmark services like delicious and magnolia. Then Firefox3 was released and the new bookmarks UI combined with the awesomebar was just much easier to use than any of the sharing extensions.</p>
<p>I never took the time to sit down and write a simple sync/push extension because I just figured that someone else would do it <img src='http://www.mikealrogers.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>It&#8217;s been a year now, it&#8217;s time for PushMarks. <a href="https://addons.mozilla.org/en-US/firefox/addon/10806/">https://addons.mozilla.org/en-US/firefox/addon/10806/</a></p>
<p>PushMarks is a simple firefox extension that pushes new bookmarks to your delicious account (more services coming). You can also initiate a &#8220;sync&#8221; which will go through all your local bookmarks and push them to delicious and also make sure any bookmarks you have on delicious are in your local bookmarks.</p>
<p>If you do a big sync, please be patient. It takes a while for all the bookmarks to get up to delicious because I have to throttle the connections for fear of being locked out of the delicious API.</p>
<p>Of course it&#8217;s all open source and up on github <a href="http://github.com/mikeal/pushmarks/tree/master">http://github.com/mikeal/pushmarks/tree/master</a> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/433/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Want to Learn Python?</title>
		<link>http://www.mikealrogers.com/archives/399</link>
		<comments>http://www.mikealrogers.com/archives/399#comments</comments>
		<pubDate>Tue, 03 Feb 2009 22:06:26 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=399</guid>
		<description><![CDATA[I&#8217;m leading an effort with the Mozilla QA team to teach community members introductory Python programming skills. I&#8217;m trying out a different approach to teaching using large group code reviews and variable programming assignments that participants can plan based on their own interest.
The lesson starts next monday and is all being organized through a Google [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m leading an effort with the Mozilla QA team to teach community members introductory Python programming skills. I&#8217;m trying out a different approach to teaching using large group code reviews and variable programming assignments that participants can plan based on their own interest.</p>
<p>The lesson starts next monday and is all being organized through a Google Group. It is open to anyone who would like to participate so if you want to learn Python come <a href="http://groups.google.com/group/mozqa-team-python-learning">on over</a>.</p>
<p>I <a href="http://quality.mozilla.org/blogs/mozqa-python-learning-project">posted about about the project on QMO</a> and you can see the <a href="http://groups.google.com/group/mozqa-team-python-learning/browse_thread/thread/2a28d6d4e6c2cdb2">discussion surrounding the lesson outline on the Google Group</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/399/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FireUnit first impressions</title>
		<link>http://www.mikealrogers.com/archives/327</link>
		<comments>http://www.mikealrogers.com/archives/327#comments</comments>
		<pubDate>Fri, 19 Dec 2008 00:37:06 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=327</guid>
		<description><![CDATA[It was pretty hard to get work done yesterday. My feed reader was filled with stories of how Apple is pulling out of Macworld and my IM and email were bursting with people asking me what I think about FireUnit.
I&#8217;m the co-author of two tools that overlap with FireUnit, Windmill and MozMill. I say overlap [...]]]></description>
			<content:encoded><![CDATA[<p>It was pretty hard to get work done yesterday. My feed reader was filled with stories of how Apple is pulling out of Macworld and my IM and email were bursting with people asking me what I think about <a href="http://fireunit.org/">FireUnit</a>.</p>
<p>I&#8217;m the co-author of two tools that overlap with FireUnit, <a href="http://www.getwindmill.com">Windmill</a> and <a href="http://code.google.com/p/mozmill">MozMill</a>. I say overlap and not &#8220;compete&#8221; because I think the tools differ enough in their goals that they don&#8217;t directly compete.</p>
<p>FireUnit has some limitations. It&#8217;s an extension to Firebug which means it will only run on Firefox. It&#8217;s focused on providing a simple API for people who are competent JavaScript programmers. I think it&#8217;s safe to say that there is an emphasis on unittesting and not functional testing, and certainly an emphasis on testing content and not chrome.</p>
<p>Something really great happens when you create a tool that embraces limitations instead of trying to be too much to too many people. You tend to be able to create better smaller purpose tools for a selection of people that have been beating themselves up trying to make tools with less limitations work for a smaller use case.</p>
<h3>The API</h3>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Simple true-like/false-like testing</span>
fireunit.<span style="color: #660066;">ok</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;I'm going to pass!&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
fireunit.<span style="color: #660066;">ok</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;I'm going to fail!&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Compare two strings - shows a diff of the</span>
<span style="color: #006600; font-style: italic;">// results if they're different</span>
fireunit.<span style="color: #660066;">compare</span><span style="color: #009900;">&#40;</span>
  <span style="color: #3366CC;">&quot;The lazy fox jumped over the log.&quot;</span><span style="color: #339933;">,</span>
  <span style="color: #3366CC;">&quot;The lazy brown fox jumped the log.&quot;</span><span style="color: #339933;">,</span>
  <span style="color: #3366CC;">&quot;Are these two strings the same?&quot;</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Compare a string using a regular expression</span>
fireunit.<span style="color: #660066;">reCompare</span><span style="color: #009900;">&#40;</span>
  <span style="color: #009966; font-style: italic;">/The .* fox jumped the log./</span><span style="color: #339933;">,</span>
  <span style="color: #3366CC;">&quot;The lazy brown fox jumped the log.&quot;</span><span style="color: #339933;">,</span>
  <span style="color: #3366CC;">&quot;Compare a string using a RegExp.&quot;</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Display the total results</span>
fireunit.<span style="color: #660066;">testDone</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>This is the example from <a href="http://ejohn.org/blog/fireunit/">John Resig&#8217;s post about FireUnit</a>. I think it illustrates how awesome the API is. I&#8217;ve always been a huge fan of this &#8220;ok&#8221; style API instead of the larger jUnit style API <a href="http://code.google.com/p/mozmill/wiki/JavascriptUnittestModule">I keep being talked in to implementing</a>. Clearly FireUnit assumes it&#8217;s audience is JavaScript programmers that can write normal expressions to handle their pass/fail logic without the hand holding of a bigger API.</p>
<p>The beauty of the comparison API you really don&#8217;t appreciate until you look at the UI.</p>
<h3>Debugging</h3>
<p>I&#8217;m most critical of tools that don&#8217;t provide sufficient debugging tools. The test debugging environment is even more important than the test authoring environment in the long run.</p>
<p>There is no better tool for debugging the web than <a href="http://www.getfirebug.com/">Firebug</a>. A big part of Windmill&#8217;s debugging strategy is it&#8217;s integration of <a href="http://www.mikealrogers.com/archives/168">Firebug</a> and <a href="http://www.mikealrogers.com/archives/78">Firebug Lite</a> because there is just no better tool in the world. Firebug ROCKS!</p>
<p>FireUnit is built as an extension of Firebug, it&#8217;s integrated in a beautiful and intuitive way so they&#8217;ve totally dodged the need for any additional debugging work outside of creating a good UI for the test bits. I&#8217;m calling this out because I think as time goes on people aren&#8217;t going to talk about the debugging experience in FireUnit because they are so used to already using Firebug for debugging their regular development and won&#8217;t recognize how good they have it debugging their tests.</p>
<h3>The UI</h3>
<p>Another benefit of embracing limitations is that you trim down your feature set to only what is actually necessary. The upside to having a simple API is that you reduce the complexity of test data you need to represent in the UI. With all that going for it I expected the FireUnit UI to be pretty good but I was <strong>still</strong> blown away.<br />
<img src="http://fireunit.org/fireunit-1.png" alt="" /></p>
<p>Look at that comparison UI!</p>
<h3>The Bad</h3>
<p>Within the limitations described above FireUnit is great but as soon as you start to cross them you&#8217;ll be disappointed.</p>
<p>Although they have some helper APIs for doing some functional testing it&#8217;s not a good functional testing tool. The tests are async which is a real pain for functional testing which is incredibly synchronous. But I think if you want to do functional testing multiple browser support is a big concern and will already preclude you from using FireUnit.</p>
<p>Although you <em>can</em> test Chrome (Mozilla Chrome not Google Chrome) I wouldn&#8217;t venture outside of unittests. If you need to start getting at anonymous nodes and simulating events on them you&#8217;re gonna see your code get about 4 times larger than a typical mozmill test.</p>
<p>Right now there doesn&#8217;t seem to be a way to run FireUnit tests in continuous integration (tinderbox, buildbot, hudson, etc). But this could easily be overcome using <a href="http://code.google.com/p/jsbridge">jsbridge</a> and I&#8217;m happy to point the FireUnit guys in the right direction <img src='http://www.mikealrogers.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>At the end of the day I think there is a huge need for a tool like FireUnit that just does what it does well and doesn&#8217;t try to be too much to too many people. A tool like this is guaranteed to make it&#8217;s users very happy and I think those users are currently unhappy with the existing set of automation tools that are trying to fill a larger feature set.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/327/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MozMill HTTP Server API</title>
		<link>http://www.mikealrogers.com/archives/319</link>
		<comments>http://www.mikealrogers.com/archives/319#comments</comments>
		<pubDate>Thu, 18 Dec 2008 22:59:41 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=319</guid>
		<description><![CDATA[One of the big questions we&#8217;ve been getting since we outlined how to write unittests in mozmill is how to serve out local files over HTTP. For quite a while I&#8217;ve had a port of mochitest&#8217;s js http server in the mozmill source tree but hadn&#8217;t written a nice API for you to be able [...]]]></description>
			<content:encoded><![CDATA[<p>One of the big questions we&#8217;ve been getting since we outlined how to write unittests in mozmill is how to serve out local files over HTTP. For quite a while I&#8217;ve had a port of mochitest&#8217;s js http server in the mozmill source tree but hadn&#8217;t written a nice API for you to be able to use it inside of your mozmill tests.</p>
<p>Ideally what I wanted was an API that worked a lot like how the dependencies work, which could serve out local files relative to the tests location on the filesystem. This way we don&#8217;t rely on any Python end to tell use what to serve out and can handle starting and stopping the server inside of the framework in the extension without any extra work from the test author. I finished the implementation a few weeks back but just <a href="http://code.google.com/p/mozmill/wiki/MozMillTestBasics#Serving_local_test_files">documented it today</a>.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> mozmill <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span> 
Components.<span style="color: #660066;">utils</span>.<span style="color: #003366; font-weight: bold;">import</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'resource://mozmill/modules/mozmill.js'</span><span style="color: #339933;">,</span> mozmill<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> elementslib <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span> 
Components.<span style="color: #660066;">utils</span>.<span style="color: #003366; font-weight: bold;">import</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'resource://mozmill/modules/elementslib.js'</span><span style="color: #339933;">,</span> elementslib<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> url <span style="color: #339933;">=</span> collector.<span style="color: #660066;">addHttpResource</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'./files'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> setupModule <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>module<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  module.<span style="color: #660066;">controller</span> <span style="color: #339933;">=</span> mozmill.<span style="color: #660066;">getBrowserController</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> testFoo <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  controller.<span style="color: #000066;">open</span><span style="color: #009900;">&#40;</span>url<span style="color: #339933;">+</span><span style="color: #3366CC;">'index.html'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>This made it in before the last release so it&#8217;s available for use right away. Enjoy <img src='http://www.mikealrogers.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/319/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Processing a JSON stream</title>
		<link>http://www.mikealrogers.com/archives/291</link>
		<comments>http://www.mikealrogers.com/archives/291#comments</comments>
		<pubDate>Thu, 04 Dec 2008 02:40:14 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=291</guid>
		<description><![CDATA[In jsbridge we have a socket that stays open constantly and the JavaScript end streams JSON objects for all the events we care about in the browser back over to Python. In jsbridge this happens asynchronously and we use asyncore since it&#8217;s available in stdlib and is pretty lightweight, but the bulk of the parsing [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://code.google.com/p/jsbridge/">jsbridge</a> we have a socket that stays open constantly and the JavaScript end streams JSON objects for all the events we care about in the browser back over to Python. In jsbridge this happens asynchronously and we use asyncore since it&#8217;s available in stdlib and is pretty lightweight, but the bulk of the parsing code is universal.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> simplejson
decoder = simplejson.<span style="color: black;">JSONDecoder</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> StreamReader<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    sbuffer = <span style="color: #483d8b;">''</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> process_read<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, data<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Parse out json objects and fire callbacks.&quot;&quot;&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">sbuffer</span> += data
        <span style="color: #008000;">self</span>.<span style="color: black;">parsing</span> = <span style="color: #008000;">True</span>
        <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">self</span>.<span style="color: black;">parsing</span>:
            <span style="color: #808080; font-style: italic;"># Remove erroneus data in front of callback object</span>
            index = <span style="color: #008000;">self</span>.<span style="color: black;">sbuffer</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'{'</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> index <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> -<span style="color: #ff4500;">1</span> <span style="color: #ff7700;font-weight:bold;">and</span> index <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff4500;">0</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">sbuffer</span> = <span style="color: #008000;">self</span>.<span style="color: black;">sbuffer</span><span style="color: black;">&#91;</span>index:<span style="color: black;">&#93;</span>
            <span style="color: #808080; font-style: italic;"># Try to get a json object from the data stream</span>
            <span style="color: #ff7700;font-weight:bold;">try</span>:
                obj, index = decoder.<span style="color: black;">raw_decode</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">sbuffer</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">Exception</span>, e:
                <span style="color: #008000;">self</span>.<span style="color: black;">parsing</span> = <span style="color: #008000;">False</span>
            <span style="color: #808080; font-style: italic;"># If we got an object fire the callback infra</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">parsing</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">fire_callbacks</span><span style="color: black;">&#40;</span>obj<span style="color: black;">&#41;</span>
                <span style="color: #008000;">self</span>.<span style="color: black;">sbuffer</span> = <span style="color: #008000;">self</span>.<span style="color: black;">sbuffer</span><span style="color: black;">&#91;</span>index:<span style="color: black;">&#93;</span></pre></div></div>

<p>The process_read function gets called every time a block of data gets read from the stream so it needs to be able to handle multiple JSON objects in a single read, objects that span multiple reads, and junk (usually spaces and return carriers) showing up between JSON objects.</p>
<p>If you wanna see this code in the wild you can check out the <a href="http://code.google.com/p/jsbridge/source/browse/trunk/jsbridge/network.py#205">jsbridge source</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/291/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using the mozmill menu API</title>
		<link>http://www.mikealrogers.com/archives/262</link>
		<comments>http://www.mikealrogers.com/archives/262#comments</comments>
		<pubDate>Wed, 03 Dec 2008 03:25:16 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=262</guid>
		<description><![CDATA[One of the first pieces of feedback we got on MozMill was that there didn&#8217;t seem to be any way to click on system menus.
System menus are defined in XUL using a special set of elements. Those are then displayed differently on every operating system and as such we can&#8217;t use tools like the MozMill [...]]]></description>
			<content:encoded><![CDATA[<p>One of the first pieces of feedback we got on MozMill was that there didn&#8217;t seem to be any way to click on system menus.</p>
<p>System menus are defined in XUL using a <a href="https://developer.mozilla.org/en/XUL/menu">special set of elements</a>. Those are then displayed differently on every operating system and as such we can&#8217;t use tools like the MozMill Inspector to get repeatable elements to click on.</p>
<p>After digging in to this problem a bit I figured out that the elements defining menus can be traversed and that they even respond properly to .click(). I then wrote thin API around the elements so that they can be easily looked up by name the way they are displayed in the menus. You can see the full documentation <a href="http://code.google.com/p/mozmill/wiki/MenuAPI">here</a>.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> mozmill <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span> 
Components.<span style="color: #660066;">utils</span>.<span style="color: #003366; font-weight: bold;">import</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'resource://mozmill/modules/mozmill.js'</span><span style="color: #339933;">,</span> mozmill<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> elementslib <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span> 
Components.<span style="color: #660066;">utils</span>.<span style="color: #003366; font-weight: bold;">import</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'resource://mozmill/modules/elementslib.js'</span><span style="color: #339933;">,</span> elementslib<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> setupModule <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>module<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  module.<span style="color: #660066;">controller</span> <span style="color: #339933;">=</span> mozmill.<span style="color: #660066;">getBrowserController</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> testMenu <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #006600; font-style: italic;">// Example 1: Click menus without testing the click</span>
  controller.<span style="color: #660066;">menus</span>.<span style="color: #660066;">File</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;New Tab&quot;</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  controller.<span style="color: #660066;">menus</span>.<span style="color: #660066;">View</span>.<span style="color: #660066;">Sidebar</span>.<span style="color: #660066;">Bookmarks</span>.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  controller.<span style="color: #660066;">menus</span>.<span style="color: #660066;">View</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;Page Style&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;No Style&quot;</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #006600; font-style: italic;">// Example 2: Click menus and test the click</span>
  controller.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">new</span> elementslib.<span style="color: #660066;">Elem</span><span style="color: #009900;">&#40;</span>controller.<span style="color: #660066;">menus</span>.<span style="color: #660066;">File</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;New Tab&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  controller.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">new</span> elementslib.<span style="color: #660066;">Elem</span><span style="color: #009900;">&#40;</span>controller.<span style="color: #660066;">menus</span>.<span style="color: #660066;">View</span>.<span style="color: #660066;">Sidebar</span>.<span style="color: #660066;">Bookmarks</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  controller.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">new</span> elementslib.<span style="color: #660066;">Elem</span><span style="color: #009900;">&#40;</span>controller.<span style="color: #660066;">menus</span>.<span style="color: #660066;">View</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;Page Style&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;No Style&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>As you can see the API is a simple chain of objects by name cascading down the different sub menus until a menu element is reached. Attribute access is just plain old JavaScript so you only need to use ["name"] syntax when looking up menus with names that contain spaces. The API is most definitely case sensitive.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/262/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Using mozmill for unittests</title>
		<link>http://www.mikealrogers.com/archives/252</link>
		<comments>http://www.mikealrogers.com/archives/252#comments</comments>
		<pubDate>Wed, 03 Dec 2008 01:16:27 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=252</guid>
		<description><![CDATA[MozMill already has some big advantages over mochitest. For one, you don&#8217;t need a special test build, you can write and run tests against any build of a Mozilla Application. You can even write and run tests just using the extension and not worry about any Python stuff until you set it up in continuous [...]]]></description>
			<content:encoded><![CDATA[<p>MozMill already has some big advantages over mochitest. For one, you don&#8217;t need a special test build, you can write and run tests against any build of a Mozilla Application. You can even write and run tests just using the extension and not worry about any Python stuff until you set it up in continuous integration.</p>
<p>MozMill already runs in &#8220;chrome&#8221;, or what Adam and I have been referring to as the &#8220;trusted&#8221; environment. All the tests that get run in MozMill are imported in this environment, which means you have access to pretty much everything in the Mozilla environment. We also have a <a href="http://code.google.com/p/mozmill/wiki/MozMillTestBasics">dependency system and a setup/teardown system for tests</a>.</p>
<p>All we were missing was a simple unittest API that can trigger failures without causing exceptions like the MozMill functional testing APIs. I looked at what others have done including <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/d-o-h-unit-testing">dojo</a>, <a href="http://mochikit.com/tests/index.html">mochikit</a>, and <a href="http://www.jsunit.net/documentation/assertions.html">jsunit</a>. </p>
<p>Fortunately MozMill gets out of any test registration and staggering stuff, it already has a well defined way of defining tests and dependencies and a clear way to run tests for debugging and continuous integration. Of all the different jum (JavaScript Unittest Module) APIs I liked jsunit the most except for the incredibly stupid idea of passing the comment argument first instead of making it an optional last argument.</p>
<p>In the end MozMill got it&#8217;s own jum which I&#8217;ve just <a href="http://code.google.com/p/mozmill/wiki/JavascriptUnittestModule">finished up documenting</a>.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> jum <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span> Components.<span style="color: #660066;">utils</span>.<span style="color: #003366; font-weight: bold;">import</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'resource://mozmill/modules/jum.js'</span><span style="color: #339933;">,</span> jum<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> testAsserts <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  jum.<span style="color: #660066;">assert</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertTrue</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertFalse</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertEquals</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'asdf'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'asdf'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNotEquals</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'asdf'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'fdsa'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNull</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNotNull</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertUndefined</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span>.<span style="color: #660066;">asdf</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNotUndefined</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'asdf'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNaN</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'a'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNotNaN</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">pass</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> testNotAsserts <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #006600; font-style: italic;">// All of these calls should fail</span>
  jum.<span style="color: #660066;">assert</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertTrue</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertTrue</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'asf'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertFalse</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertFalse</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'asdf'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertEquals</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'asdf'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'fdsa'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNotEquals</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'asdf'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'asdf'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNull</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNotNull</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertUndefined</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'asdf'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNotUndefined</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span>.<span style="color: #660066;">asdf</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNaN</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">assertNotNaN</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'f'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  jum.<span style="color: #660066;">fail</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>All of these functions take an optional comment argument which can be any JSON serializable value (string, int, obj, array, null, bool).</p>
<p>What we&#8217;re missing right now is the http local file server. I&#8217;ve already ported mochikit&#8217;s web server to be a resource but I&#8217;m still working on a better API for using it. What we want is for tests to simply define local relative paths that should be mounted at different local url namespaces and the framework can handle starting and stopping the server if necessary. This API will be finished in the next few weeks and ready for MozMill 1.0 (which we&#8217;re looking at pushing out before January 1st).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/252/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>MozMill 1.0RC2 w/ Test Recorder</title>
		<link>http://www.mikealrogers.com/archives/248</link>
		<comments>http://www.mikealrogers.com/archives/248#comments</comments>
		<pubDate>Sun, 30 Nov 2008 00:24:51 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=248</guid>
		<description><![CDATA[Last week we finished up the 1.0RC2 release of MozMill.
The biggest new feature was is the Test Recorder. You can now hit the Record button and use the Application normally and create a test outline. I say &#8220;test outline&#8221; because it&#8217;s usually necessary after creating a recorded test to go in and fill it up [...]]]></description>
			<content:encoded><![CDATA[<p>Last week we finished up the <a href="https://addons.mozilla.org/en-US/firefox/addon/9018">1.0RC2</a> release of <a href="http://code.google.com/p/mozmill/">MozMill</a>.</p>
<p>The biggest new feature was is the Test Recorder. You can now hit the Record button and use the Application normally and create a test outline. I say &#8220;test outline&#8221; because it&#8217;s usually necessary after creating a recorded test to go in and fill it up with a few conditional wait calls, like waitForElement and waitForPageLoad. If you don&#8217;t the test runs too fast and ends up failing pretty quickly. We&#8217;re working on some future code to pick up things like new page loads so that we can add those waits in a recorded test but for now you&#8217;ll have to do them by hand.</p>
<p>We also have significantly improved some of the documentation.</p>
<ul>
<li><a href="http://code.google.com/p/mozmill/wiki/MozMillTestBasics">http://code.google.com/p/mozmill/wiki/MozMillTestBasics</a></li>
<li><a href="http://code.google.com/p/mozmill/wiki/CommandLine">http://code.google.com/p/mozmill/wiki/CommandLine</a></li>
<li><a href="http://code.google.com/p/mozmill/wiki/MenuAPI">http://code.google.com/p/mozmill/wiki/MenuAPI</a></li>
</ul>
<p>I&#8217;ll be writing some more blog entries this week on using MozMill for writing and running different kinds of tests.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/248/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Introducing&#8230; jsbridge</title>
		<link>http://www.mikealrogers.com/archives/210</link>
		<comments>http://www.mikealrogers.com/archives/210#comments</comments>
		<pubDate>Tue, 28 Oct 2008 07:10:37 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=210</guid>
		<description><![CDATA[I started working on this library months ago and it&#8217;s been getting some use already. I spoke about it a bit at Mozilla Summit and as a result there was a post on Ajaxian, but for the most part I&#8217;ve been holding off on promoting it until I solidified the API and pushed out a [...]]]></description>
			<content:encoded><![CDATA[<p>I started working on this library months ago and it&#8217;s been getting some use already. I spoke about it a bit at Mozilla Summit and as a result there was a post on <a href="http://ajaxian.com/archives/jsbridge-powering-mozilla-with-python">Ajaxian</a>, but for the most part I&#8217;ve been holding off on promoting it until I solidified the API and pushed out a solid release.</p>
<p><a href="http://code.google.com/p/jsbridge">jsbridge</a> is a Python to JavaScript translation interface for Mozilla applications. It&#8217;s implemented as an extension and can be dynamically installed and launched in a new &#8220;clean&#8221; profile using <a href="http://code.google.com/p/mozrunner">mozrunner</a>.</p>
<p>You can call functions and set variables in any window in any scope from Python and those objects are returned and represented as Python objects (which are just classes that inherit from Python base types). There are obvious limitations for assignment and representations in Python, you can really only send objects over the bridge that can be JSON serialized, but it does support assignments by reference so you can move around and manipulate anything that&#8217;s already there.</p>
<p>But the most interesting feature is the event system. The event system is available as a resource from inside the Mozilla environment (in other words you can import it from your Firefox extension). Events fired on the JavaScript end are serialized as JSON and sent to the Python side. This means you can add listeners in Python to events fired from the Mozilla JavaScript environment.</p>
<p>This is a big deal. It means we can write significantly cleaner tools. We can now create tools solely as Firefox extensions that don&#8217;t require any special Python code to run, but have code that checks if jsbridge is installed and send pertinent events over the bridge for continuous integration. No more printing to console and parsing in Python, no more outputting to log files and parsing them, no more scripts calling scripts and OH MAN MY HEAD HURTS!</p>
<p>The documentation has some great <a href="http://code.google.com/p/jsbridge/wiki/UsingJSBridge#JavaScript_(most_likely_to_be_placed_in_your_extension_code)">examples</a>.</p>
<p>For a little snippet of the events system in the wild here is some new <a href="http://code.google.com/p/mozmill">mozmill</a> Python code that sends all the events to the Python logger.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">logging</span>
logger = <span style="color: #dc143c;">logging</span>.<span style="color: black;">getLogger</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;mozmill&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> jsbridge <span style="color: #ff7700;font-weight:bold;">import</span> events
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> LoggerListener<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    cases = <span style="color: black;">&#123;</span>
        <span style="color: #483d8b;">'mozmill.pass'</span>:   <span style="color: #ff7700;font-weight:bold;">lambda</span> obj: logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Test Pass: '</span>+<span style="color: #dc143c;">repr</span><span style="color: black;">&#40;</span>obj<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
        <span style="color: #483d8b;">'mozmill.fail'</span>:   <span style="color: #ff7700;font-weight:bold;">lambda</span> obj: logger.<span style="color: black;">error</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Test Failure: '</span>+<span style="color: #dc143c;">repr</span><span style="color: black;">&#40;</span>obj<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#125;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">class</span> default<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, eName<span style="color: black;">&#41;</span>: <span style="color: #008000;">self</span>.<span style="color: black;">eName</span> = eName
        <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__call__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, obj<span style="color: black;">&#41;</span>: logger.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">eName</span>+<span style="color: #483d8b;">' :: '</span>+<span style="color: #dc143c;">repr</span><span style="color: black;">&#40;</span>obj<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__call__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, eName, obj<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">cases</span>.<span style="color: black;">has_key</span><span style="color: black;">&#40;</span>eName<span style="color: black;">&#41;</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">cases</span><span style="color: black;">&#91;</span>eName<span style="color: black;">&#93;</span><span style="color: black;">&#40;</span>obj<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">cases</span><span style="color: black;">&#91;</span>eName<span style="color: black;">&#93;</span> = <span style="color: #008000;">self</span>.<span style="color: black;">default</span><span style="color: black;">&#40;</span>eName<span style="color: black;">&#41;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">cases</span><span style="color: black;">&#91;</span>eName<span style="color: black;">&#93;</span><span style="color: black;">&#40;</span>obj<span style="color: black;">&#41;</span>
&nbsp;
events.<span style="color: black;">add_global_listener</span><span style="color: black;">&#40;</span>LoggerListener<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">logging</span>.<span style="color: black;">basicConfig</span><span style="color: black;">&#40;</span>level=<span style="color: #dc143c;">logging</span>.<span style="color: black;">ERROR</span><span style="color: black;">&#41;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/210/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ubiquity command for docs.python.org</title>
		<link>http://www.mikealrogers.com/archives/196</link>
		<comments>http://www.mikealrogers.com/archives/196#comments</comments>
		<pubDate>Fri, 24 Oct 2008 01:01:34 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=196</guid>
		<description><![CDATA[
Ubiquity rocks! A month or so ago I completely removed the search box from Firefox and started solely using ubiquity for searches.
The one thing that I really missed was a python doc search that I used to have for the search box. For a while I just used the awesome bar to perform google and [...]]]></description>
			<content:encoded><![CDATA[<link rel="commands" href="http://www.mikealrogers.com/wp-content/uploads/python-ubiquity.js" name="Python Ubiquity Command" />
<p>Ubiquity rocks! A month or so ago I completely removed the search box from Firefox and started solely using ubiquity for searches.</p>
<p>The one thing that I really missed was a python doc search that I used to have for the search box. For a while I just used the awesome bar to perform google and history searches for python docs but that basically broke when Python 2.6 was released since all the old docs.python.org urls that google returns break because 2.6 has completely new docs provided by <a href="http://sphinx.pocoo.org/">Sphinx</a>.</p>
<p>So today I took a break from my &#8220;normal&#8221; work to write a ubiquity command to bring up the search page from docs.python.org for your input text. You can see the source <a title="python ubiquity command" href="http://www.mikealrogers.com/wp-content/uploads/python-ubiquity.js">here</a> and you should be able to install it by viewing this <a href="http://www.mikealrogers.com/archives/196">blog post</a>.</p>
<p>In the future I&#8217;d like to do better previews of the searches but I can&#8217;t seem to find any web API for searching docs.python.org.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/196/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MozMill Beta2 Released</title>
		<link>http://www.mikealrogers.com/archives/183</link>
		<comments>http://www.mikealrogers.com/archives/183#comments</comments>
		<pubDate>Mon, 13 Oct 2008 19:52:35 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=183</guid>
		<description><![CDATA[Last week we finished up the Beta2 Release for MozMill.
You can install it from AMO.
We&#8217;ve been gathering feedback from our Beta1 release and pushed out another incremental beta release before the big push for MozMill 1.0 RC1.
One important thing we did was improve the inspector workflow. It&#8217;s much smother clicking on an element and coming [...]]]></description>
			<content:encoded><![CDATA[<p>Last week we finished up the Beta2 Release for MozMill.</p>
<p>You can <a href="https://addons.mozilla.org/en-US/firefox/addon/9018">install it from AMO</a>.</p>
<p>We&#8217;ve been gathering feedback from our Beta1 release and pushed out another incremental beta release before the big push for MozMill 1.0 RC1.</p>
<p>One important thing we did was improve the inspector workflow. It&#8217;s much smother clicking on an element and coming back to the Inspector. The inspector also gives you much more information now, including what document you should be passing the Elem you create and what method you should use to create a controller for the window you&#8217;re testing.</p>
<p><a href="http://www.mikealrogers.com/wp-content/uploads/2008/10/mozmill.png"><img class="alignnone size-full wp-image-185" title="MozMill Beta2 Inspector" src="http://www.mikealrogers.com/wp-content/uploads/2008/10/mozmill.png" alt="" width="530" height="655" /></a></p>
<p>Lot&#8217;s of bug fixes, special thanks to Tony, Tracy and a big hug to Farhad for feature suggestions and filing bugs against beta1.</p>
<p>This release does not include the new framework that hooks up to <a href="http://code.google.com/p/jsbridge">jsbridge</a>, and therefor isn&#8217;t ready for full continuous integration, that&#8217;s now in trunk getting worked on for the RC1 release.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/183/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windmill 0.9.1 Released</title>
		<link>http://www.mikealrogers.com/archives/168</link>
		<comments>http://www.mikealrogers.com/archives/168#comments</comments>
		<pubDate>Mon, 13 Oct 2008 17:51:27 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Windmill]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=168</guid>
		<description><![CDATA[I didn&#8217;t think we&#8217;d be doing any notable windmill releases until 1.0. Boy was I wrong!
Seriously Faster
On Wednesday Adam messaged me and said that the windmill startup time was too slow. He was right, we&#8217;ve know about this for a while but hadn&#8217;t put a lot of serious thought in to how we could reduce [...]]]></description>
			<content:encoded><![CDATA[<p>I didn&#8217;t think we&#8217;d be doing any notable windmill releases until 1.0. Boy was I wrong!</p>
<h4>Seriously Faster</h4>
<p>On Wednesday Adam messaged me and said that the windmill startup time was too slow. He was right, we&#8217;ve know about this for a while but hadn&#8217;t put a lot of serious thought in to how we could reduce it.<br />
The issue here was was that we have about 50 JavaScript files that need to get loaded for windmill to start.</p>
<p>Enter windmill-compressor, a new url namespace we added that concats all the js windmill needs in to one file and minifies it. We do this dynamically when windmill starts up, because adding a &#8220;build&#8221; step would just be too&#8230;.. Java.</p>
<p>That reduced the startup time from 5-10 seconds to around 2 seconds. But that wasn&#8217;t good enough. We saw that most of that startup time was blocking waiting for the compressor to finish, so I threaded it when we start the windmill service and it does the compression while we wait for the browser to start up.</p>
<p>In all, windmill startup times are about 10x faster than 0.9!</p>
<p>Adam also decided to make our page load wait code a bit more aggressive which made not only startup times faster but all of our tests!</p>
<h4>Native JavaScript Test Framework</h4>
<p>We tied up the loose ends on the JavaScript testing framework and it can now shutdown all of windmill in it&#8217;s own teardown, hello continuous integration for native JavaScript tests <img src='http://www.mikealrogers.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>This was the last thing holding us back from promoting this along side the Python test authoring library.</p>
<h4>We Love Firebug</h4>
<p>In 0.9 we introduced Firebug Lite integration for windmill on all browsers. But when you&#8217;re using Firefox you probably still want to use the full Firebug extension, which is easy enough to integrate since we use <a href="http://code.google.com/p/mozrunner">mozrunner</a> for Firefox launching.</p>
<p>Windmill now has a &#8220;firebug&#8221; command line argument that installs the full Firebug<br />
extension when launching Firefox.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/168/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MozMill Beta Released</title>
		<link>http://www.mikealrogers.com/archives/159</link>
		<comments>http://www.mikealrogers.com/archives/159#comments</comments>
		<pubDate>Mon, 29 Sep 2008 04:35:34 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=159</guid>
		<description><![CDATA[It&#8217;s no secret that shortly after I started at Mozilla I began working on an ambitious automation project. The project, called MozMill, is a tool that can be used for full UI automation of all Mozilla applications. In time this means not just Firefox but Thunderbird, Flock, Songbird, etc.
We hit a major milestone last week [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s no secret that shortly after I started at Mozilla I began working on an ambitious automation project. The project, called <a href="http://code.google.com/p/mozmill/">MozMill</a>, is a tool that can be used for full UI automation of all Mozilla applications. In time this means not just Firefox but Thunderbird, Flock, Songbird, etc.</p>
<p>We hit a major milestone last week when I finished implementation of the &#8220;Lookup&#8221; object, which uses a custom expression syntax that can define lookup for any element, even anonymous elements created by XBL that aren&#8217;t in the DOM. We also made some crucial additions to the Inspector UI;  generation of expressions for the new Lookup object, better XPath, validation for all the expressions the inspector generates, and enhanced fallback logic. After about an hour of testing I couldn&#8217;t find a single element the Inspector couldn&#8217;t generate an expression for testing, which means we can simulate all events on all elements in any Mozilla application.</p>
<p>Late last week we finally pushed our Beta release, and now the extension is up on <a href="https://addons.mozilla.org/en-US/firefox/addon/9018">AMO and ready for anyone interested to install and start poking around.</a></p>
<p>Clint has also written some great documentation; a <a href="https://wiki.mozilla.org/QA/TDAI/Gristmill/Mozmill_Tutorial">great tutorial</a> and a fairly complete <a href="https://wiki.mozilla.org/QA/TDAI/Gristmill/Gristmill_API">API reference</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/159/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Firebug Lite in Windmill</title>
		<link>http://www.mikealrogers.com/archives/78</link>
		<comments>http://www.mikealrogers.com/archives/78#comments</comments>
		<pubDate>Tue, 09 Sep 2008 05:12:29 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Windmill]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=78</guid>
		<description><![CDATA[Everyone knows how awesome Firebug is. But for those times you have the unfortunate task of debugging in a browser that isn&#8217;t Firefox the Firebug team recently put out a new release of Firebug Lite.
For some time now we&#8217;ve always had a shell in Windmill for debugging but it was never as nice as the [...]]]></description>
			<content:encoded><![CDATA[<p>Everyone knows how awesome <a href="http://getfirebug.com/">Firebug</a> is. But for those times you have the unfortunate task of debugging in a browser that isn&#8217;t Firefox the Firebug team recently put out a new release of <a href="http://getfirebug.com/lite.html">Firebug Lite</a>.</p>
<p>For some time now we&#8217;ve always had a shell in Windmill for debugging but it was never as nice as the Firebug shell and maintaining that code was kind of a pain. In the <a href="http://www.getwindmill.com/archives/210">recent 0.8.2</a> release of Windmill we dropped our old shell code and fully integrated Firebug Lite so that whenever you need to debug a test in any browser you can open Firebug Lite in the target application by clicking a single link in the Windmill IDE.</p>
<p style="text-align: center;"><img class="size-full wp-image-85 aligncenter" title="windmillide1" src="http://www.mikealrogers.com/wp-content/uploads/2008/09/windmillide1.png" alt="" /></p>
<p style="text-align: center;"><img class="size-full wp-image-86 aligncenter" title="windmillfirebug2" src="http://www.mikealrogers.com/wp-content/uploads/2008/09/windmillfirebug2.png" alt="" width="539" height="470" /></p>
<p style="text-align: center;">
<p>I can&#8217;t even begin to explain how much easier this is going to make writing and debugging tests in Windmill.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/78/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Introducting&#8230; mozrunner</title>
		<link>http://www.mikealrogers.com/archives/36</link>
		<comments>http://www.mikealrogers.com/archives/36#comments</comments>
		<pubDate>Fri, 29 Aug 2008 19:35:24 +0000</pubDate>
		<dc:creator>mikeal</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.mikealrogers.com/?p=36</guid>
		<description><![CDATA[Although the task of starting and stopping a given Mozilla Applications is taken on by all Mozilla tools there is no shared code for accomplishing this task. Historically most Mozilla tools have just been part of the main repository and act as &#8220;scripts&#8221; instead of more independent Python libraries and/or Extensions. This meant that shared [...]]]></description>
			<content:encoded><![CDATA[<p>Although the task of starting and stopping a given Mozilla Applications is taken on by all Mozilla tools there is no shared code for accomplishing this task. Historically most Mozilla tools have just been part of the main repository and act as &#8220;scripts&#8221; instead of more independent Python libraries and/or Extensions. This meant that shared code could only really be accomplished through cut and paste.</p>
<p>The task of just starting and stopping the Mozilla Applications is harder than it would seem, particularly when it comes to stopping. There&#8217;s also a bunch of other things you wanna do to Mozilla Applications when you&#8217;re launching them; set preferences, install plugins, build new clean profiles and use them, add command line arguments to the launch, etc.</p>
<p>mozrunner is a Python library that is independent of any particular Mozilla application source repository and is hosted at <a href="http://code.google.com/p/mozrunner">http://code.google.com/p/mozrunner</a> . The library takes on the task of starting, configuring and stopping Mozilla Applications (only tested against Firefox right now but it <em>should</em> work with Thunderbird, Songbird, etc. and patches are welcome). We used this library when developing the new Gristmill suite of test automation tools and it&#8217;s been wonderful to work with.</p>
<p>The current documentation is over on the google code wiki; <a href="http://code.google.com/p/mozrunner/wiki/UsingMozRunner">http://code.google.com/p/mozrunner/wiki/UsingMozRunner</a> , there is a lot more that you can do with mozrunner that still isn&#8217;t up in the documentation and I plan on just adding it as people ask me how to do things.</p>
<p>If you have Python and <a href="http://peak.telecommunity.com/DevCenter/setuptools#installing-setuptools">setuptools</a> installed you can just install it via easy_install.</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">$ easy_install mozrunner</pre></div></div>

<p>It should find your local Firefox install by default, so just running mozrunner from the command line should launch Firefox. You can also check out the &#8211;help for some simple configuration and testing of the launcher script.</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">$ mozrunner --help</pre></div></div>

<p>But of course, you shouldn&#8217;t be executing the script from within Python, and you&#8217;ll find some information in the docs about how to simply import the mozrunner Python library and embed the launching and configuration in to your tool.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikealrogers.com/archives/36/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
