Disclaimer: this is an automatic aggregator which pulls feeds and comments from many blogs of contributors that have contributed to the Mono project. The contents of these blog entries do not necessarily reflect Novell's position.

July 03

Finally post my PGCon2008 pictures!!


Hi all,

I finally post my pictures from PGCon2008.

You can see them on my picasa web album.

iPhone 3G/2.0 or OpenMoko or Andriod

Two revolutionary phones coming out at the same time and a third that people will think is revolutionary (just kidding).

My thoughts coming from my thoughts a developer and what I know from my experience as a OSS developer and enlightened consumer myself. I’ve done lots of mobile development in the past. Limited by J2ME or Brew, horrible systems that limit my break in to the market put in my cell providers, having to get approval to run the software on my own phones or customers phones from the manufacture and the cell company using signatures and keys (killing open source efforts for the phones). It’s a nasty game.

OpenMoko

Very interesting. I defiantly will be ordering the OpenMoko Freerunner as soon as it comes out to evaluate after it comes out. I’ve been following the project and tinkering with the developer kit in the past. It’s Linux, I can do what I want, its not sold by the cell company, and so it’s mine to do what I want and it’s free for me to change it. This appeals to me as a developer and is great for customers because it brings variety and customization, cheaper software and better quality.

The Freerunners hardware could be better, but they are trying to use components with only hardware with publicly documented interfaces or using open standards or provide free drivers, so it’s hard. Only USB 1.1 USB, no camera, a limited to 256mb of internal flash hurt (with SD card support we may be able to get up to 8gb). The hardware is open as well as OpenMoko publishes the CAD designs for everything, and its packed full of interfaces to stick add on new things.

iPhone 2.0 and 3G

I was one of the first to stand in line to get the iPhone. I was one of the first to run the activation hacks and jailbreak it. I seen the potential of the platform for myself. When apple anonocced the developer program I was extreemly happen until I read all the restrictions. Feels like everything I faced before. I’ve signed up and have been rejected by the developer program, so no chance of my application running on through app store (thankfully the jailbreaking community wasn’t deterred by this program so I will continue my development plans.

I will still likely upgrade my iPhone to the 3G version though. One thing is that the iPhone chick magnet of hotness ( just kidding :-) ).

Andriod

Its neat, but I don’t think it will get as accepted highly by the development community. It’s going to be hard to convince people to rewrite their applications since Adriod’s system pretty requires it to run since everything must run on their VM. Sure its linux and its going to open, but its like BSD open and the people selling the phones are likely to lock it down for there versions preventing modification, so no native code will not be able to be introduced. Just not doing it for me.

howtoqk0.png

Aaron and Banshee

Today I walked into Aaron's office unannounced and I just saw him glowing. Like a girl that has been kissed for the first time, like a donkey in the spring.

A voice in the background was narrating Banshee features, and I was wondering just what is that noise?

As I went around to his monitor to see what he was watching and listening to, I saw this Linux.com review on Banshee that included a screencast/podcast.

He was *so* excited that he was actually watching it in three computers at once.

I could not believe it.

Three computers at once. One, two and three. All playing the podcast. At the same time.

I was speechless.

From economic mastermind to flattered developer.

He said to me: "I have never seen a production of such caliber" as he listened to the background music in the above podcast.

I just stood there quietly. Unsuspectingly recovering the Twix office supply.

Moonlight 0.7 Installers

Yesterday I forgot to point to the actual page to install the Moonlight plugins.

You can download the latest plugin from here. Just like the last release, these plugins are compiled without ffmpeg support.

The source code is available here.

You can track the progress and try out a few applications yourself from our Moonlight Status page.

Cleaning up the patches list


Wow! I think our patch list is too big and I need to do something about it! :)

Sorry all who sent your patches and didn't have them applied yet. I'm starting to run through the list and reviewing/discussing/applying them.

If you have any patch you think needs urgent attention, please let me know.

Thanks in advance.

July 02

Disqus WordPress Widget Plugin

Today I made my baby steps in PHP (yuck) and I hacked up a Disqus WordPress Widget Plugin. It can be found here, where you will find the download and the same information as below. Description This plugin adds a new widget which can show statistics for your blog’s/forum’s Disqus comments: most popular discussions, top commenters, recent [...]

Moonlight 0.7 is now Available

A new release of Moonlight is now available. The team has been working very hard on improving the performance of Moonlight as well as improving our compatibility with Microsoft's Silverlight.

Get your copy here. Source code is moon-0.7.tar.bz2.

This release will also work with both Firefox 2.0 and Firefox 3.0. We have also switched our installation system to use signed XPIs, but we will also require a browser restart (we could not figure out a way of avoiding this).

Some of my favorite work that happened on this cycle is the effort to improve our multi-browser support, work towards supporting WebKit and Opera is underway and will improve over time. This work benefitted from our own work to support both Firefox 2.0 and 3.0 in the plugin.

Windowless mode (the mode that allows blending of HTML content and Silverlight content) is vastly improved but is only available on Firefox 3.0. This is a feature that is used extensively by Silverlight designers.

More details from the release:

  • Webkit loads the plugin (kangaroo, lewing)
  • The stream/downloader/request/response logic (used for downloading media) has been been almost entirely moved from the browser bridges into libmoon, with the browsers providing subclasses. (kangaroo, sde)
  • Finally add argument checking to all wrapped plugin objects (fejj).
  • Windowless mode fixes (lewing, toshok)
  • Plugin event handling fixes (lewing)
  • Engine
    • Many clock/animation framework fixes. We now pass both animation matrix tests, and many, *many* other bugs (and regressions) have been fixed. (mdk).
    • Bug fixes in the Stroke{Collection}.HitTest and Stroke{Collection}.Bounds code (toshok, sde).
    • Namescope merging fixes (sde, jackson)
    • Parser fixes, and changes paving the way for 2.0 work (jackson)
    • Fix mouse event bubbling behavior (toshok)
  • Media
    • Big, big strides in our media framework and the various (file, http, mms) downloaders, (fejj, rolf, kangaroo, fer)
    • MMS stream selection (kangaroo)
  • Performance
    • Shape caching and bounds computation reduction (spouliot)
    • Geometry bounds work (spouliot)
    • Fast path for position updates (Canvas.Left/Canvas.Top) (toshok)
    • Improved temporary cairo surface bounds (lewing)
    • Glyph rendering speedups (fejj)
    • Resort by ZIndex as a dirty pass (toshok)
  • Silverlight 2.0
    • work is progressing. A very simple 2.0 application successfully ran. (miguel, jackson, sde).
  • Moonlight 0.7 released

    We have just released Moonlight 0.7 to the public.

    Get your copy here.

    This new version of Moonlight works on both Firefox 2.0 and 3.0 and sports some significant changes from 0.6:

    • Webkit loads the plugin (kangaroo, lewing)
    • The stream/downloader/request/response logic (used for downloading media) has been been almost entirely moved from the browser bridges into libmoon, with the browsers providing subclasses. (kangaroo, sde)
    • Finally add argument checking to all wrapped plugin objects (fejj).
    • Windowless mode fixes (lewing, toshok)
    • Plugin event handling fixes (lewing)
  • Engine
    • Many clock/animation framework fixes. We now pass both animation matrix tests, and many, *many* other bugs (and regressions) have been fixed. (mdk).
    • Bug fixes in the Stroke{Collection}.HitTest and Stroke{Collection}.Bounds code (toshok, sde).
    • Namescope merging fixes (sde, jackson)
    • Parser fixes, and changes paving the way for 2.0 work (jackson)
    • Fix mouse event bubbling behavior (toshok)
  • Media
    • Big, big strides in our media framework and the various (file, http, mms) downloaders, (fejj, rolf, kangaroo, fer)
    • MMS stream selection (kangaroo)
  • Performance
    • Shape caching and bounds computation reduction (spouliot)
    • Geometry bounds work (spouliot)
    • Fast path for position updates (Canvas.Left/Canvas.Top) (toshok)
    • Improved temporary cairo surface bounds (lewing)
    • Glyph rendering speedups (fejj)
    • Resort by ZIndex as a dirty pass (toshok)
  • Silverlight 2.0
    • work is progressing. A very simple 2.0 application successfully ran. (miguel, jackson, sde).
  • July 01

    .NET and XPath

    So I’m working on this XPath presentation for my team at work. I was trying to hack up a sample using some of the more interesting XPath functions, like string-join. PHP’s DOMXPath throws a fit when I use this function so I cracked open MSDN and saw that XPathNavigator in the 2.0 framework [...]

    June 30

    Support for 100+ webcams in Linux 2.6.27 (USB Video Class Driver)

    According to a thread on the Linux uvcvideo driver mailing list if everything goes well we will see it included in the 2.6.27 kernel! What is this uvcdriver and why is this great news? According to Wikipedia: “The USB video device class (also USB video class or UVC) is a USB device class that describes devices capable [...]

    My Bachelor degree and the importance of the Free and Open Source Software

    I have successfully completed my Honours Bachelor of Science (HA Bsc) in Software Engineering degree with the highest possible mark/result - a First (yay!). My studies took place in the University of Hull (United Kingdom) for the duration of 3 years. Lovey department/university in a suckabolic city. But who cares about the city anyway. 3 years… [...]

    Diablo III !!!!!!111111ONEONEONEELEVEN

    Dudes, I am so freakin excited! Diablo III is official now - http://www.blizzard.com/diablo3! Edit: I should probably point you to the good coverage by Ars Technica at http://arstechnica.com/news.ars/post/20080630-eight-years-in-the-making-blizzard-unveils-diablo-iii.html. Edit2: “It’s official” == it has been started / is in developement

    PreGuadecs events

    Yes! I'm going to GuadecES this week and to GUADEC next week! I'll be giving one talk in both, talking about our Novell's accessibility project.

    But this weekend has been not less exciting than Guadecs promise to be! I'm not used to blog about personal things but I can't resist to try to make someone laugh a bit!

    Firstly, on Saturday I went to Rock In Rio festival in Madrid. Many concerts, specially I liked Mando Diao and Carlinhos Brown. Here I'm in the place where Mando Diao played:



    It's amazing how big this "Rock City" is. It's like being in a recreational park, but with many scenarios for concerts.

    The band El Canto del Loco also played but I didn't like them very much. Also, guess who was playing when I fell asleep:



    Tokio Hotel! I didn't know this band but actually had already heard their most famous song, which happens to have the same name of a program that I'm using very much lately: Monsoon. That song is not that bad but they had to play it the last one in order to prevent the people from fleeding in the first run. The band leader is actually a kind of vain awful transvestite!:



    Now a cronicle about sunday: although I used to be a member of the Leo Bassi's AntiFootball League (I may be the only spaniard that doesn't like soccer) I went to see the Spain VS Germany match with some friends. Anyways, what I like about soccer is when you really feel you belong to a team, not in the case of those football clubs that play in the Spanish league: if I ever encourage Real Madrid to win a day in my life, that day will be a day in which there are only Madrid-born players in the team, not others (of course this hasn't got anything to do with racism, it's just that I think the competition is more interesting this way, and also because I'm not interested in players being bought and sold by astronomic quantities...). Well, in case you don't know, we won, and we went to the center of Madrid to celebrate it. Since I haven't got any rojigualda flag (just republicans) or red t-shirts, I had to mix with the people like if I was an orange dutch!:



    To finish the post, I just want to give a link to a very special song that I've come to know recently (I can't stop playing it!):


    CatPeople - Behind

    Exception Performance Part 2

    Last time we saw that CLR exception handling is significantly slower than HotSpot exception handling. This time we'll look at two very variations of the ExceptionPerf1 microbenchmark that significantly affect performance.

    I've highlighted the changes.

    Variation 1

    public class ExceptionPerf2 {
      public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
          try {
            Integer.parseInt("");
          }
          catch (NumberFormatException x) {
          }
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
      }
    }

    Variation 2

    public class ExceptionPerf3 {
      static NumberFormatException exc;
      public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
          try {
            Integer.parseInt(null);
          }
          catch (NumberFormatException x) {
            exc = x;
          }
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
      }
    }

    Results:

          HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
    ExceptionPerf1 111 14743 3590 537
    ExceptionPerf2 140 15735 10761 36309
    ExceptionPerf3 112 14946 9728 24107


    .NET/Mono results with IKVM 0.36

    Why do these small changes have such a big perf impact?

    Both these changes result in additional stack trace data being collected. IKVM has some optimizations that prevent gathering stack traces in very specific circumstances. Normally when you create a Java exception object, the Throwable constructor will call Throwable.fillInStackTrace(). However, since this is a very expensive operation, IKVM tries to remove this call when it is unnecessary (i.e. when it sees that you immediately throw the exception and the exception type doesn't override Throwable.fillInStackTrace()). Additionally, in Java an exception object will always have the complete stack trace, but a .NET exception only has the stack frames from the throw to the catch site. This means that at the catch site IKVM will collect the rest of the stack trace, unless the exception object isn't used (as in the ExceptionPerf1 microbenchmark).

    The time it takes to collect a stack traces obviously depends on the call stack depth, so let's look at a microbenchmark to measure that effect:

    class ExceptionPerf4 {
      public static void main(String[] args) {
        nest(Integer.parseInt(args[0]));
      }

      static void nest(int depth) {
        if (depth > 0) {
          nest(depth - 1);
        } else {
          run();
        }
      }

      static void run() {
        Exception x = new Exception();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
          x.fillInStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
      }
    }

    Results:

    Depth     HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
    1 64 2930 4611 19377
    10 85 3814 6787 34895
    100 380 12500 27935  
    1000 3543      

    For the curious, the IKVM implementation of Throwable.fillInStackTrace() is essentially new System.Diagnostics.StackTrace(true);

    Next time we'll wrap things up.

    June 29

    Gendarme News Week #26, 2008

    at 6/28/2008 8:10:41 PM poupou said...

    Added ReplaceIncompleteOddnessCheckRule to Gendarme. This will detect bad checks for oddness, like ((x % 2) == 1), which wont work for negative numbers. The fixed version would be ((x % 2) != 0) but an even better one, avoiding the modulo, is: ((x & 1) == 1).
    BTW did I say it rained today ?!?


    at 6/28/2008 2:13:09 PM poupou said...

    with jbevain benediction (pun intended ;-) I started applying Gendarme performance rules into Cecil.
    I found a bug in a rule (already fixed) and few false positives that I'll need to check upon...


    at 6/27/2008 10:23:26 PM poupou said...

    Earlier today Zoltan, aka vargaz, made a nice commit to change a few Type.GetType(string), which requires reflection, into faster typeof(x).
    How many more are there in Mono ? 84 tonight (hopefully less tomorrow) according to Gendarme new rule: AvoidTypeGetTypeForConstantStringsRule.


    at 6/27/2008 8:45:45 PM poupou said...

    Lot of gray today, but no rain yet!!! (and I'm doing my best to ignore this weekend weather reports)
    Anyway I added a new Gendarme rule, ReviewUseOfInt64BitsToDoubleRule, to check if the use of BitConverter.Int64BitsToDouble looks ok (i.e. converting bits) instead of a integer to double routine.
    Like a lot of the recent rules the idea for this one comes from #findbugs - a java-based tool.


    at 6/25/2008 10:13:49 PM poupou said...

    It *almost* did not rain today, except after diner :| since I don't like watching rain...
    I refactored Dan's AvoidThrowingBasicExceptionsRule to let me implement the very similar, code wise, DoNotThrowReservedExceptionRule for Gendarme.
    nestor is making great progress (for GSoC 2008) but I'll let him the honor to show this to everyone ;-)


    at 6/23/2008 8:24:28 PM poupou said...

    I just added DoNotRoundIntegersRule to Gendarme and a few instruction rocks to go along. Good news: no defect was found inside Mono class libraries. Bad news: it rains everyday


    at 6/16/2008 9:21:46 PM poupou said...

    Still rainy :-( Anyway I committed ReviewUselessControlFlowRule for Gendarme. This is another rule to check for typos (like an extra ';' after a condition) and a great way to find empty code blocks (like forgotten TODO ;-). There are a bit over 100 of them inside Mono right now...


    Read older news...

    more news, less typing

    It's been a while since I blogged here (again) but I got some good excuses... like:

    1. Nestor did a great job to resume the Gendarme Rule Day (which saved me a post ;-)
    2. I started using ohloh journal - which JB kinda announced (saving me precious keystrokes again :-)

    Right now I'm using the journal to to describe all new things, mostly rules, being added into Gendarme. It works well (it's fast) but does not reach as many people as Monologue. My original idea was to post, from time to time, summaries in my own blog. I failed that - I guess I'm not so good at duplicating content ;-)

    Since I'm (hopefully) better at coding (than either blogging or duplicating) I created a small application (to learn a bit about XLinq) that reads the Gendarme Journal and create a "weekly news" RSS entry. Look for it soon on monologue.

    PayPal sandbox doesn't work

    As a software developer I've worked with a lot of APIs and developer tools over the years and had many good experiences and a few bad ones. The bad ones are where you waste a lot of time trying to get something to work and it just doesn't do what its supposed to. These kinds of things make you angry and make you resent the vendor because they make you look bad as a developer and they cost you a lot of time, and time is money. The worst cases are those where you have no real choice, you have to use the vendors products or APIs.  The latest bad experience I've had is with PayPal. Their developer sandbox just doesn't work and its been eating up my time trying to make it work. I have followed the API documentation closely and am 100% sure I'm doing the right things in my code but it doesn't work. Yet, how can I ignore PayPal if I want to implement ecommerce? I can't because they are the most popular provider. I simply have to get it working. Maybe I will have to test on their production site and then issue refunds. This is what some others have resorted to if you read their forums. You end up paying the transaction fees though even if you do issue refunds. Its a wonder to me that PayPal is so dominant given these shortcomings. I've implemented google checkout and Authorize.NET and they both worked as expected using their sandboxes.

    I've created a Camtasia movie here showing the problems, but to summarize:

    PayPal offers 2 products, PayPal Express and PayPal Pro/ Direct Pay. The Direct Pay allows you to charge the customer right from your own site by letting them enter their credit card info, this costs you $30/month to enable the service. Express checkout doesn't have this monthly fee but requires the user to pay at the paypal site with their paypal account.

    Using the NVP (Name Value Pair) API to process Express checkout, the process is.

    1. Make a call to the PayPal NVP web service using the SetExpressCheckout call. You recieve back a paypaltoken and then you redirect the user to paypal passing this same token. This call works as expected, you get the token and you redirect.

    2. After the customer pays at PayPal, PayPal redirects them back to your designated page and passes the paypaltoken again. Its the same token as the one returned from the previous call to SetExpressCheckout. Next you are supposed to call GetExpressCheckoutDetails passing the same token back to PayPal. This call fails with the error "Security header is not valid". When you look this up or google it, its supposed to mean that you did not pass the correct API credentials, but believe me, I'm passing the right credentials and its the same credentials that worked fine in the call to SetExpressCheckout. If the call to GetExpressCheckoutDetails worked as its supposed to, the next step would be to call DoExpressCheckoutPayment which is where the order would be completed.

    To use the DirectPay API you need to accept the billing agreement which would cost you $30/month on production but should be free on the sandbox. However, when you click the I Agree button in the sandbox account it doesn't work so you can't get your sandboz account enabled to use the DirectPay API.

    So, in short, the PayPal sandbox just doesn't work. You can't reliably test the Expess Checkout or the DirectPay API. You would think the so called industry leader in payment processing could do a better job with this. PayPal are you listening? Please please please fix this crap and stop making me waste my time. Are you really going to make me use the production site for testing? Is that some angle to help you squeeze me for $30/month or are you just incompetant?

    UPDATE: In case you think I'm being too hard on PayPal, I captured another little video to show how difficult it is to file a support ticket. I have not figured out how to do it yet. I had this same problem yesterday which is why I resorted to blogging in hopes of getting some attention from PayPal to address the sandbox problems.

     



    Joe Audette  ...

    June 28

    My reading list

    I haven't blogged for a while, so here is a lame blog post listing feeds I am currently subscribed to. I am a Liferea user, by the way. I tried to migrate to online feed reader, but somehow it didn't seem more convinient.

    Software projects


    I am subscribed to two software project feeds. One is of course IronPython, which I mainly use to monitor the issue tracker. I would prefer mail notification for this, but it's not implemented in CodePlex.

    Another is PyPy. Quoting somebody on YouTube (hah!), "PyPy is the most ambitious project any language has ever had", and I believe it. Even if you don't believe it, it's well worth subscribing if you are into programming languages. By the way, the YouTube video is PyPy - Automatic Generation of VMs for Dynamic Languages.

    Programming language developers


    I am subscribed to blogs of developers implementing programming languages. For IronPython, I have Dino Viehland and Martin Maly on the list. For JRuby, Charles Nutter and Ola Bini are great.

    Just like about everybody else, I read John Lam to follow IronRuby. From Mono developers, I only read Jb Evain. If signal-to-noise ratio for me were a bit higher, I would have read Miguel de Icaza -- but I don't.

    For JVM, I read Gary Benson and John Rose, although both are usually over my head. Last two blogs in this category are from GCC developers (among other things): Ian Lance Taylor and Tom Tromey. Surprisingly, Ian and Tom are usually not over my head! I thank them for their generosity -- I am entirely sure that they are capable of writing posts inscrutable to me. :)

    Others


    Being a science fiction fan, I read Charles Stross. There are many great science fiction writers, but that set somehow doesn't seem to intersect with the set of great bloggers a lot.

    Being a fan of mathematics, I read Terence Tao. I don't pretend to understand technical materials there, but occasional posts directed to the "public" is simply great. For computer science fans (as opposed to software engineering!) I recommend Scott Aaronson. Be sure to check out his lecture notes!

    I read Alp Toker for no particular reason. His posts always have been enjoyable to me. I temporarily have Antonio Cangiano on the roll, mainly not to miss his Ruby shootout.

    Korean blogs


    That leaves me some Korean blogs. Hye-Shik Chang, a Python developer and a FreeBSD port maintainer, is the best Korean blogger in his niche. Park, Seong Chan is a theoretical physicist who writes great approachable posts on physics news. Kim Gyuhang is a progressive columnist. I sympathize with his political views. He is also my writing model for how to write clear and affecting Korean prose.

    June 27

    Another Generic Sharing Update

    Since my last report on generic code sharing I chased down a few bugs we uncovered when trying out IronPython 2.0. That new version uses the Microsoft Dynamic Language Runtime, which extensively utilizes generics. One issue we came across was how to figure out the actual method for a delegate when only the [...]

    Coming Soon - The mojoPortal Store

    Back in October of 2006 when I first launched my company, Source Tree Solutions to work full time on mojoPortal, I had kind of a fuzzy business plan with the main idea being that I would make revenue by offering consulting around the free mojoPortal product. I guess in my wide eyed optimism I thought that doing this kind of consutling would improve mojoPortal and in fact it did to some extent. A few customers actually sponsored development for things that improved mojoPortal for everyone. But most of the consutling was really for things that were not of any general benefit beyond the customer's needs, so in some cases I felt like taking on this work was actually slowing me down from progress on improving mojoPortal. Forming a business around consulting means you always have to be taking on more projects to keep the business going because you don't make any money unless you are doing billable work. Now I am in the process of shifting my strategy to sell some premium features on top of the free mojoPortal core product. I think that selling some products in order to generate revenue will be better because it will pay for the free time I need to keep improving the mojoPortal. Consulting will remain a part of my business model but my plan is to keep it very limited goig forward.

    So with this changing strategy in mind I've been working feverishly to get my first product completed so that I can open up a Store here on mojoPortal.com in early July and begin selling it. The first feature for sale will be a more advanced Event Calendar that allows selling tickets to events. Following that I plan to build a Form Wizard that allows users to easily create forms to capture arbitrary data. I also plan a Fund Raiser feature and an add on package for Web Farm support. I have a lot of ideas for premium features, but my main goal is to just get enough revenue rolling in to allow me to keep improving the core. There are a lot of planned improvements for the core that I'm eager to complete, like built in support for tagging, comments, and content versioning so that they can easily be enabled for any feature with little effort. Eventually I'd like to open the store up so that other developers can also sell products there too, so that it can be a market place something like snowcovered.com which sells add ons for DNN.

    One of the reasons I chose to implement a commerce enabled feature as my first product was so that I could figure out which pieces of the commerce architecture need to b re-usable. We already have a WebStore project that I will be using to sell my premium products and this WebStore is one of the free open source features of mojoPortal. So far the WebStore is very rudimentary, it can only sell download products and its really a bare bones implementation for the product catalog at the moment. The project was originally started under a sponsorship by BrainBeacon but was never completed fully because they went out of business before ever opening a store. Its hard to really polish up a complex feature like ecommerce unless you are actually using it for business or supporting a customer who is using it. So using it to sell my own products will lead to a lot of improvement in the WebStore feature. I've been doing a lot of re-factoring in the WebStore to get the re-usable pieces built into mojoPortal core so they can be used across features. For example, Country List, State List, Currency List, Language List and their administrative features were originally in the WebStore projects but I've moved them into the core of mojoPortal because they will be needed by other features. Support for Payment gateways like Google Checkout and PayPal are also being moved into the core so they can be re-used by any feature that wants to implement ecommerce. Since my first product will be an Event Calendar that allows selling tickets it will need to leverage a lot of the same ecommerce code that the WebStore does. Rather than re-implement it in every feature it has forced me to think about the best way to make most of it easily re-usable.

    Implementing this more advanced Event Calendar has also led me to other improvements in the core of mojoPortal. For example one of the features in my new Event Calendar is support for recurring events. When you create a recurring event it actually creates event instances going out x number of years. Since  events are also searchable using the site search, you have to update the search index for each created event as well. What I found was that creating events in rapid succession due to recurrence could lead to some problems due to the way I was handling the indexing of items. The indexing was triggered by the saving of the event then code to update the index was spawned on a new thread so that it doesn't block the UI. Under some circumstances the writing to the index was not in the proper sequence and errors could occur. So I implemented a queue in the database so that items to be indexed could be queued and then processed in batch on a background thread while keeping the sequence correct because everything is processed in queue sequence.

    Another thing that got improved in the core as I implemented this new Event Calendar is module settings, which is just a place to store feature specific settings for instances of a feature. In a number of the mojoPortal features we have support for google maps, but some of the settings needed for google maps were not well supported by module settings. For example the google maps api defines some constants for the Map Type like G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP, etc. When I first enabled support for specifying the map type, it was done in module settngs by entering the constant in a textbox like this:

    pretty yucky and not user friendly since its easy to put something incorrect there and nothing to tell the user what is acceptable. So as much as this bothered me I could not conceive of shipping a paid product with this kind of setting so I implemented ISettingControl as a way to introduce a possibility to use a custom UserControl for this setting and now for all features that use the google map the setting looks like this:

    much better implemented as a dropdown list! Actually not shown in the screen shot is I also implemented a dropdown for the zoom level so that it is limited to the range of acceptable values.

    So, in short, developing features to sell has made me think more deeply about what is needed in the core of mojoPortal to support 3rd party feature development more easily, because its made me think more like a third party.

    I haven't blogged much this month because I've been so busy working to get this feature completed and to get the store opened, but thught I should go ahead and post this to let people know what I'm doing. Several people have asked recently what happened to the store demo site as it is currently off line. I will have that site back up soon. I just have a little more re-factoring of the WebStore code to do and I will setup the demo store again.

    I'm very excited about the new store opening soon and will announce it here in the blog as soon as its open. There will also be anew release of mojoPortal soon with the improvements I've mentioned above as well as a few bug fixes and skin tweaks to better support Firefox 3.



    Joe Audette  ...

    June 26

    The end is nigh

    Just recently is finished “Svartir Englar” by Ævar Örn Jósepsson (I read the Dutch version) although I was pretty bored after the first twenty pages. After finishing the book I realized that I should have stopped after those initial pages since this has just been a waste of my time. The question then came up [...]

    Changing scm vs cooler software?

    While I do love git, mercurial, bzr and all their hype, I can’t help but wonder if the time spent on deciding on a DVCS is keeping people from writing cool software. With the curiosity if GNOME is decadent, perhaps we should just hack for a while and see what comes of it. I [...]

    Linux Virtualization

    I’ve been using VirtualBox for some months now. It’s pretty slick and doesn’t get in my way too much. Just for the heck of it I’ve been experimenting with a few other similar systems: OpenVZ, vserver, KVM, and Xen. OpenVZ and KVM are the only two I’ve tinkered with long enough to [...]

    Perian: Codec solution for my quicktime no audio with video files


    After having some problems playing audio from some video files, I found this thread on macosxhints which talked about Perian. And voilà! It worked perfectly. It has a simple double click install procedure which adds a new item on your preferences pane. 

    Very nice! :)

    Debugger integration in MonoDevelop

    Many people has been asking about the status of the debugger integration in MonoDevelop, so I thought it would be a good idea to post a quick status report.

    The short answer is that we are working on it. The debugger integration work has started, and there is already support for breakpoints, stepping, call stack view, current frame selection, basic variable watch window, and attaching/detaching to/from running processes. All this is working in MonoDevelop from SVN (still with some stability issues).

    And here are some big news: we are integrating not only MDB (the Mono debugger), but also GDB, and thanks to the debugger abstraction layer we built in MD, we'll be able to use the same GUI for both debuggers. Two debuggers for the price of one!

    We are going to do a MonoDevelop release next week. However, this release will not include the debugger integration because it still depends on Mono and MDB from SVN and we would not be able to package it. If you want to try the debugger (beware, this is work in progress), you have to do the following:
    • Get and build Mono from SVN.
    • Get and build the Mono Debugger from SVN.
    • Get MonoDevelop from SVN.
    • At the MonoDevelop's top-level directory, run './configure --select'. Make sure the extras/MonoDevelop.Debugger.Mdb add-in is selected (and/or extras/MonoDevelop.Debugger.Gdb if you want GDB support).
    • Build MonoDevelop.
    If you only want to try GDB, you don't need Mono and MonoDebugger from SVN, getting latest MonoDevelop is enough.

    I underestimated the power of query comprehensions

    In my last post, I said I'd write the sample in C# to compare to F#. Well, I grossly underestimated the power of query comprehensions. The C# version is almost the same length (formatting differences, mainly). I'm surprised and impressed. (Or maybe I'm writing F# like I'd write C#.) Edit: I think maybe sequence expressions could cut it down a bit...

    ...But... C# still can't do discriminated unions efficiently or effectively ;).


        1 // crudcreatecompare.cs: Generates LINQ CRUD table fields using the horribly named DatabaseBase code

        2 //

        3 // Tables look like: [Table(Name="dbo.Accounts")]

        4 // Columns look like this:

        5 //  [Column(Storage="_AccountName", DbType="VarChar(128) NOT NULL", CanBeNull=false, IsPrimaryKey=true)]

        6 //  [DataMember(Order=1)] // Exists if serialization is turned on; used to order key parameters

        7 // Emits:

        8 //  public static readonly TableHelper<Account, String> Accounts =

        9 //      CreateTable(dc => dc.Accounts, a => a.AccountName);

       10 

       11 using System;

       12 using System.Collections.Generic;

       13 using System.Data.Linq.Mapping;

       14 using System.IO;

       15 using System.Linq;

       16 using System.Reflection;

       17 using System.Runtime.Serialization;

       18 

       19 class Program

       20 {

       21     static void Main()

       22     {

       23         Console.WriteLine(

       24             new Program().generate(

       25             "C:\\yourlinq.dll"));

       26     }

       27 

       28     string generate(string asmpath)

       29     {

       30         var asm = Assembly.LoadFrom(asmpath);

       31         var lines = from t in asm.GetExportedTypes()

       32                     let ta = getAttr<TableAttribute>(t)

       33                     where ta != null

       34                     let name = pluralize(ta.Name.Replace("dbo.", ""))

       35                     orderby name

       36                     select genTable(t, name);

       37         return joinStrings("", lines);

       38     }

       39 

       40     string genTable(Type t, string tableName)

       41     {

       42         var keyProps =

       43             from p in t.GetProperties()

       44             let c = getAttr<ColumnAttribute>(p)

       45             where c != null && c.IsPrimaryKey

       46             let dm = getAttr<DataMemberAttribute>(p)

       47             orderby dm == null ? 0 : dm.Order

       48             select p;

       49         var tw = new StringWriter();

       50         tw.WriteLine("public static readonly TableHelper<{0}, {1}> {2} =",

       51             t.Name,

       52             joinStrings(", ", keyProps.Select(p => p.PropertyType.Name)),

       53             tableName);

       54         tw.WriteLine("\tCreateTable(dc => dc.{0}, {1});",

       55             tableName,

       56             joinStrings(", ", keyProps.Select(p => "a => a." + p.Name)));

       57         tw.WriteLine();

       58         return tw.ToString();

       59     }

       60 

       61     string joinStrings(string sep, IEnumerable<string> items)

       62     {

       63         return string.Join(sep, items.ToArray());

       64     }

       65     string pluralize(string s)

       66     {

       67         return s.EndsWith("s") ? s : s + "s";

       68     }

       69 

       70     T getAttr<T>(ICustomAttributeProvider icap)

       71     {

       72         var a = icap.GetCustomAttributes(typeof(T), true);

       73         return a.Length == 0 ? default(T) : (T)a[0];

       74     }

       75 }

    LINQ to the CRUD CreateTable generator in F#

    With the DatabaseBase and TableHelper classes, you still have to generate a CreateTable field per table. Why do it by hand? I wrote an F# script to generate the statements. I must say, I'm loving F# more than I had hoped. The more I learn, the better it gets. I've noticed (even in C#) that using a functional style generally means less errors. This script worked without bugs the first time (i.e., as soon as it compiled), which is pretty cool (granted, it's not big, but I'm sure if I had tons of for loops, I woulda messed up somewhere). Maybe this weekend I'll try writing it in C# just to compare (pretty sure it'll be more than 59 lines!). And I'll preempt comments about readability: Yes, it may be difficult to read if you don't know F#, but more on that later...

    I'd love feedback as to making it more "functional"; years of imperative programming don't die quickly. Also, I'm not very happy with the definition of chooseAttr, but I can't seem to get it to infer the type I want otherwise.

    Anyways, here's the code. You'll need to specify the references when compiling: -r "C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.Linq.dll" -r "C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System.Runtime.Serialization.dll"


        1 // crudcreatetable.fsx: Generates LINQ CRUD table fields using the horribly named DatabaseBase code

        2 //

        3 // Tables look like: [Table(Name="dbo.Accounts")]

        4 // Columns look like this:

        5 //  [Column(Storage="_AccountName", DbType="VarChar(128) NOT NULL", CanBeNull=false, IsPrimaryKey=true)]

        6 //  [DataMember(Order=1)] // Exists if serialization is turned on; used to order key parameters

        7 // Emits:

        8 //  public static readonly TableHelper<Account, String> Accounts =

        9 //      CreateTable(dc => dc.Accounts, a => a.AccountName);

       10 

       11 #light

       12 open System

       13 open System.Reflection

       14 open System.Data.Linq.Mapping

       15 open System.Runtime.Serialization

       16 

       17 let getAttr<'target, 'a when 'a :> ICustomAttributeProvider> (ty : 'a) =

       18     match List.of_array (ty.GetCustomAttributes(typeof<'target>, true)) with

       19         | a::_ -> Some (a :?> 'target)

       20         | [] -> None

       21 let chooseAttr<'target, 'a when 'a :> ICustomAttributeProvider> (ty : 'a) =

       22     match getAttr<'target,_> ty with

       23         | Some(a) -> Some(ty,a)

       24         | None -> None

       25 

       26 let joinStrings (sep:string) items = items |> Seq.fold1 (fun acc x -> acc + sep + x)

       27 let pluralize (name:string) = if name.EndsWith("s") then name else name + "s"

       28 

       29 let generate(asmpath:string) =

       30     let genTable (t:Type, tableName) =

       31         let keyProps =

       32             t.GetProperties()

       33             |> Seq.choose (chooseAttr<ColumnAttribute,_>)

       34             |> Seq.filter(fun (p,c) -> c.IsPrimaryKey)

       35             |> Seq.map(fun (p,_) -> p, getAttr<DataMemberAttribute, _> p)

       36             |> Seq.orderBy(function | _,Some(dm) -> dm.Order | _ -> 0)

       37             |> Seq.map (fun (p,_) -> p)

       38         let tw = new IO.StringWriter()

       39         let pn fmt = Printf.twprintfn tw fmt

       40         pn "public static readonly TableHelper<%s, %s> %s ="

       41             t.Name

       42             (joinStrings ", " (keyProps |> Seq.map (fun p -> p.PropertyType.Name)))

       43             tableName

       44         pn "\tCreateTable(dc => dc.%s, %s);"

       45             tableName

       46             (joinStrings ", " (keyProps |> Seq.map (fun p -> "a => a." + p.Name)))

       47         pn ""

       48         tw.ToString()

       49 

       50     let asm = Assembly.LoadFrom asmpath // Don't use ReflectionOnly 'cause it won't resolve dependencies

       51     asm.GetExportedTypes ()

       52         |> Seq.choose (chooseAttr<TableAttribute,_>)

       53         |> Seq.map (fun (t,ta) -> t, ta.Name.Replace("dbo.", "") |> pluralize)

       54         |> Seq.orderBy (fun (t,_) -> t.Name)

       55         |> Seq.map genTable

       56         |> Seq.fold1 (+)

       57 

       58 generate "C:\\yourlinq.dll"

       59     |> Console.WriteLine

    LINQ to the CRUD RTM

    [Reposting because it appears to have been deleted somehow.]

    A bit ago, I posted some info on doing CRUD operations using LINQ: http://www.atrevido.net/blog/2007/08/26/A+LINQ+To+The+CRUD.aspx

    This is a lightweight way (no codegen at all, only 2 lines of code per table) to get some CRUD stuff with LINQ. It's not the most efficient or fantastic way of doing things, but it works fine in the several projects we've used it so far. And we get to use C# 3's expression trees, which is a fantastic and under-exploited feature. At any rate, it does show that doing disconnected work with LINQ is trivial.

    The code I posted was for Beta 2 and no longer works. I've since added a few new features, but the basic idea remains the same as before. I'm just posting the new code as I've gotten a few emails and one comment about the old code no longer working.

    DatabaseBase.cs (10.47 KB)

    While working on it in a real project, I started using our Tuple struct, so you'll need that too:
    Tuple.cs (2.8 KB)

    As Scott Peterson pointed out, this class doesn't implement IEquatable<T>. Just add it and call the == operator.

    As always I welcome any criticism.

    June 25

    Ohloh Stats

    So, I was told this morning that I'm on Ohloh.net's top 15 "Most Experienced C Programmers" list.

    Sure enough, there I am:


    Updated: Turns out, after I had consolidated my accounts, I'm now #9 on the list.

    Recent Hacks: irc2wiki.pl and xchat-nick-pidgin-status.py

    The Mono a11y team has weekly iteration meetings in IRC, and we post the logs to the Mono wiki. Our version of MediaWiki doesn't automatically prettify IRC logs, so for awhile I was using Jamie Zawinski's irc2html.pl to create HTML tables. Today I hacked it up to produce MediaWiki tables instead. I call it irc2wiki.pl. Fixes welcome (or better suggestions).

    Also, I now live on IRC. Some people prefer to get me through IM, so I always have Pidgin running, but my online presence is mostly reflected in my IRC nick. I'm forgetful, so I kept noticing that I was "available" in Pidgin even though my IRC nick was "sandy|lunch", or that when I changed my nick from "sandy|brb" to "sandy" my Pidgin status would stay the same. I decided to automate that shit. Based on a bunch of useful code from Arstechnica's Ryan Paul, I present to you my first xchat plugin, xchat-nick-pidgin-status.py:


    #!/usr/bin/env python

    # Sets Pidgin status from XChat nick, assuming you use a style like:
    # mynick => Available (status "Workin")
    # mynick|busy => Away (status "busy")
    # Hobbled together by Sandy Armstrong from code
    # written by Ryan Paul (segphault) of Ars Technica:
    # http://arstechnica.com/reviews/apps/pidgin-2-0.ars/4
    # http://arstechnica.com/journals/linux.ars/2007/08/29/send-twitter-updates-from-xchat-using-python

    import xchat, dbus

    # Describe the plug-in metadata for XChat
    __module_name__ = "Pidgin Status Plug-in"
    __module_version__ = "1.0"
    __module_description__ = "Set Pidgin status according to XChat nick"

    # Specify status ID values
    STATUS_AVAILABLE = 2
    STATUS_AWAY = 5


    def nick(words, word_eol, userdata):
    # Get new nick
    if len(words) < 2:
    return None
    new_nick = words[1]

    # Check for status
    pipe_index = new_nick.find("|")
    if pipe_index > 0 and pipe_index < len(new_nick):
    message = new_nick[pipe_index + 1:]
    # set away with status message
    set_status("", STATUS_AWAY, message)
    else:
    # set available
    set_status("", STATUS_AVAILABLE, "Workin")


    def set_status(name, kind, message):
    # Create a new saved status with the specified name and kind
    status = purple.PurpleSavedstatusNew(name, kind)
    # Associate the specified availability message with the new saved status
    purple.PurpleSavedstatusSetMessage(status, message)
    # Activate the new saved status
    purple.PurpleSavedstatusActivate(status)


    # Initiate a connection to the Session Bus
    bus = dbus.SessionBus()

    # Associate Pidgin's D-Bus interface with Python objects
    obj = bus.get_object(
    "im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject")
    purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")


    # Associate the nick function with the /nick command in XChat
    xchat.hook_command("nick", nick)

    MS150 update and Thanks!!!

    I’m always amazed by the generosity of my friends and family at this time of year. With only a week and a half, I not only raised the minimum for participation in this year’s ride but had to change my goal twice! [...]

    PulseAudio: A Solution In Search of a Problem

    I upgraded the Linux OS on my laptop yesterday so that I had a more up-to-date GNOME installation such that I could actually build Evolution from SVN and hack it a bit to solve some annoyances I've been having. However, this is for another blog post.

    So... PulseAudio. W. T. F.

    All day yesterday I'd been wondering why my sound volume was so low even though I had cranked it all the way up to 100%. Since I was mostly focused getting work done yesterday, I didn't spend any time investigating until last night when I was forced to do so.

    I don't remember the exact order of things, but I did watch an episode of Harsh Realm in Xine while also IM'ing some friends in Pidgin, but the sound was so low I could barely hear anything. So a friend on IRC suggested I kill pulseaudio and restart it as this supposedly would help fix the "wonkyness" (evidently I'm not the only one with PulseAudio problems).

    This worked for a while, long enough to play the DVD iirc, but afterward I had no sound. So I thought "well, I guess this is just more PulseAudio 'wonkyness', so let me kill pulseaudio again". This time when I killed it, my sound card got flooded with every audio event that had happened over the hour or so I was running Xine. Yay. (that was a sarcastic yay in case you couldn't tell)

    Audio worked again for a bit. At one point, a friend IM's me a link so I clicked it and no browser started up (which seemed a bit odd). Tried it again, still nothing. So I figured "ok, I'll just launch firefox from my gnome-terminal and see if that prints any errors". No errors, but it did just hang. Oh goodie. Ctrl-C'd and killed pulseaudio again. At this point my friend IM'd me again which made Pidgin completely lock up:


    PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
    26422 fejj 20 0 3054m 1.3g 27m D 198 33.2 18:55.68 pidgin

    So the issues of memory usage are perfect for another rant blog post, but the point is that pidgin is completely locked. I can't even kill -9 it (I tried multiple times).

    I had to Ctrl+Alt+F1, login as root, and `init 3`

    At this point I was so frustrated that I uninstalled each and every package with pulseaudio in the name before going back to X.

    Low and behold, after that my audio works flawlessly (well, the Pidgin IM audio events make some crackling which I don't recall happening before I reinstalled, but I can live with it - especially since other audio seems crisp).

    So yea... the stuff that the Linux Hater says is all true. He even complained about audio under Linux a while back (couldn't remember which entry it was with a quick look over the entry names).

    The point of this story is that PulseAudio appears to be a solution in search of a problem (quite common in the land of Linux afaict).

    As I was bitching about this to a hacker friend of mine, he asked me "isn't PulseAudio for sound mixing or something? So multiple programs can all play audio at the same time?".

    Nope, because ALSA seemed to do mixing just fine for me in the past.

    A quick Google search for PulseAudio reveals that it is supposed to allow fancy stuff like redirecting sound to another host machine for playing.

    ...just as I suspected: a solution in search of a problem.

    Seriously though, who the hell needs that feature on their desktop/laptop machines? No one, that's who. The only people who might need that are thin clients - so why install it by default? Why not just have the sysadmins for those thin-client networks set this up?

    PulseAudio is a clusterfuck for basic desktop audio needs afaict.

    Sigh.

    Update: Apparently I offended the PulseAudio developer with my "it's a solution in search of a problem" statement. For that, I apologize. A number of people have explained what exactly it is supposed to be solving. Unfortunately, none of the problems it is solving seem to be problems I need solved (maybe my sound cards in all my machines have hardware mixing support? I don't know. Or maybe dmix is plenty good enough for me).

    I also apologize because apparently some (not all) of the problems I was experiencing were because of brokenness in my distro (or so it is suspected). For that, I also apologize.

    However, I still get the feeling that PA is not quite ready for wide desktop adoption because people on other distros are having some of the same problems I had and this is not good.

    I'd expect a similar rant from people if Evolution's current IMAP provider was replaced with my IMAP4 provider. As nice as my IMAP4 provider replacement is for my usage, there are no doubt new problems that it might currently have over the old implementation that would break things for some people. (Hence why I have not pushed for it to replace the old IMAP provider until I'm sure it is ready.)

    Also, this was tagged as a rant. I had every right to be frustrated because things weren't working like they have worked Just Fine(tm) for me for years. I've had to put up with far worse personal attacks on myself and software I've been involved with over the years than anything I said on this blog (and lets face it, this was not a personal attack aimed at the PA devs - it was just me venting my frustration with a piece of software), so I think some people took this post way too personally.

    Exception Performance Part 1

    One area where IKVM performance is much worse than HotSpot is in throwing and catching exceptions. This blog is the first of three that will look into why this is the case.

    We start out with two microbenchmarks to highlight the differences.

    Java

    public class ExceptionPerf1 {
      public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
          try {
            Integer.parseInt(null);
          }
          catch (NumberFormatException x) {
          }
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
      }
    }

    C#

    using System;

    class ExceptionPerf1 {
      public static void Main(string[] args) {
        int start = Environment.TickCount;
        for (int i = 0; i < 100000; i++) {
          try {
            throw new Exception();
          }
          catch (Exception) {
          }
        }
        int end = Environment.TickCount;
        Console.WriteLine(end - start);
      }
    }

    Results:

          HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
    Java* 111 14743 3590 537
    C#   11139 2605 187


    *.NET/Mono results with IKVM 0.36

    This shows that the situation on the CLR is pretty bad. If you care about exception throwing performance, please complain to Microsoft instead of to me. Although I expect that they'll tell you not to throw so many exceptions. ;-)

    On the next episode we'll see that the above microbenchmark is actually a best case scenario for IKVM and we'll see how things can get much worse...

    Useful Tool

    Andy Malakov wrote an Ant task for ikvmc. It also contains a doclet that can generate an xml mapping file that contains all the parameter names that ikvmc can then attach to the .NET methods (ikvmc already does this for methods with debugging information, but that doesn't work for abstract methods).

    Good stuff!

    June 24

    Tasque 0.1.6 Released

    Yesterday I released Tasque 0.1.6 to a legion of hungry Linux users. I can't believe it's been three months since 0.1.5 was released! You can expect to see 0.1.7 a lot quicker, especially because there are some good patches in bugzilla that just need a bit of review.

    As you might expect, Tasque 0.1.6 is our best release yet. There's a new task entry widget at the top of the main window, and due dates are parsed right out of the task text. Plus, there are the usual handful of bug fixes, including a few crashers.

    Give it a try, and let us know what you think!



    And today I knew Shiira...


    And I loved it!

    I know I said about using firefox 3 and liking it, but after some days I was not confortable with it. I think I could get more. After some research, I found about Shiira on google search and decided to give it a try.

    I loved its speed. Also it needs very few resources. At least processor power. I'm still investigating memory usage which I thought it was a little too much for some pages I opened. 
    I also liked it because if uses WebKit rendering engine which I think is faster than gecko. Also, it is opensource, so I'm very happy and for while doesn't need to use the proprietary Safari.


    For while I'm enjoying it very much.

    Shiira homepage: http://shiira.jp/en.php

    June 23

    User pain

    After reading Jonathan's interesting post about bug classification, I got interested in the article behind it, finding a very promising approach. It has been an issue for us during the last months and this approach looked good to the team.

    After making a few samples with some variations on the formula, we decided to give it a try, so I implemented a few changes during the weekend to support it on our internal defect tracking tool (it