<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Medallia Blog</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/" />
    <link rel="self" type="application/atom+xml" href="http://blog.medallia.com/atom.xml" />
   <id>tag:blog.medallia.com,2008://1</id>
    <link rel="service.post" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1" title="Medallia Blog" />
    <updated>2008-05-11T21:04:46Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.2</generator>
 
<entry>
    <title>iPhone and Movies Mashup</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2008/05/iphone_and_movies_mashup.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=35" title="iPhone and Movies Mashup" />
    <id>tag:blog.medallia.com,2008://1.35</id>
    
    <published>2008-05-11T02:02:59Z</published>
    <updated>2008-05-11T21:04:46Z</updated>
    
    <summary>Mashup Camp winner helps you make wise movie rental decisions Never rent a bad movie again. I created iMoveMash.com after renting one bad movie too many at the local supermarket&apos;s DVD rental kiosk. The free-wifi sign near that kiosk and...</summary>
    <author>
        <name>Al Nevarez</name>
        
    </author>
            <category term="iPhone" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p><strong>Mashup Camp winner helps you make wise movie rental decisions</strong></p>

<p>Never rent a bad movie again.  I created <a href="http://imoviemash.com" target="_blank">iMoveMash.com</a> after renting one bad movie too many at the local supermarket's DVD rental <a href="http://www.dvdplay.com/">kiosk</a>.  The free-wifi sign near that kiosk and my long time <a href="http://www.japaninyourpalm.com" target="_blank">interest</a> in mobile applications sparked an idea to help movie lovers  make better rental decisions.  </p>

<p>The resulting mobile web application integrates 7 data sources, including DVDPlay's kiosk content, Blockbuster's latest movies, <a href="http://www.imdb.com/">IMDB</a> movie ratings, <a href="http://www.kids-in-mind.com/">Kids-In-Mind</a> movie ratings, YouTube, Yahoo Movies, and Google Maps.</p>

<p><a href="http://imoviemash.com" target="_blank">iMovieMash</a> lists the kiosk's or Blockbuster's new movies in descending IMDB movie rating order (best movie first).  Each movie I list is also a link to Yahoo Movies and search results from YouTube's API.  The YouTube search query is biased in a way that is likely to return trailers or videos related to the movie itself.  When clicked, the YouTube results launch the native YouTube application in the iPhone or iTouch.</p>

<p><a href="http://imoviemash.com" target="_blank">iMovieMash</a> took 2nd place at <a href="http://www.mashupcamp.com/">Mashup Camp 6</a>, where I demo-ed the application dozens of times in 5 minute "speed geeking" sessions.  That was a good bit of fun, and re-enforced the concept that successful products have a simple message, solve a real problem, and look good.</p>

<p>The application was developed with <a href="http://en.wikipedia.org/wiki/Perl">Perl</a> for the backend and the <a href="http://code.google.com/p/iui/">IUI</a> iPhone framework for the front end.  It looks best on the iPhone or iTouch, but runs fine on a Blackberry or any web browser.  Just goto http://imoviemash.com.</p>

<div><img alt="mmlist.png" src="http://blog.medallia.com/mmlist.png" width="210" /> &nbsp;&nbsp;&nbsp;&nbsp;<img alt="mmyt2.png" src="http://blog.medallia.com/mmyt2.png" width="210" /></div>]]>
        <![CDATA[<p>Al Nevarez<br />
Product Manager & sometimes hacker</p>]]>
    </content>
</entry>
<entry>
    <title>The Run of a Lifetime</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/12/the_run_of_a_lifetime.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=34" title="The Run of a Lifetime" />
    <id>tag:blog.medallia.com,2007://1.34</id>
    
    <published>2007-12-15T08:10:22Z</published>
    <updated>2008-02-05T09:04:49Z</updated>
    
    <summary>Sometimes I just don&apos;t quite understand my fellow colleague Max.. One day at work, during lunch he suddenly goes; &quot;I&apos;ve decided to run a marathon.. in 6 weeks... in Athens&quot;. First we thought he was kidding, only to find out...</summary>
    <author>
        <name>Snorre Helvik</name>
        
    </author>
            <category term="Personal Achievements" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>Sometimes I just don't quite understand my fellow colleague Max.. One day at work, during lunch he suddenly goes; "I've decided to run a marathon.. in 6 weeks... in Athens". First we thought he was kidding, only to find out he was serious. Secondly he though he was crazy, which turned out to be fairly correct. He said he accidentally came across the event on the web and figured, "ah, this seems like something for me"!? Hmm, the guy hasn't really been running the past few years, and except for our weekly soccer practice I'd guess he hasn't done any exercise at all lately, so how could he possibly think that marathon is something for him? Well, there's only one way to find out, so two weeks later I decided to join the madness! So, that's how the story begins; One marathon, two participants, four weeks! 42 km can't be that bad, can it?</p>]]>
        <![CDATA[<p><strong>:: The motivation ::</strong></p>

<p>It's the day after I decided to join, and it's time to get motivated. I was a bit worried about my recent injury in my back and that my knee had been bad for a couple of years, so I figured I could ask my physiotherapist on my scheduled meeting that day. When I told her I was going to run marathon.. in 4 weeks.. first, she looks at me with a you-gotta-be-kidding look, and somewhat kindly explaining that running marathon was NOT the smartest thing I could do in my situation.. My back would probably survive, but my knee is most likely to get a lot worse! But after a while she, after realizing I was already at the point of no return, was indeed helpful and gave me some advice to help me along the way. I proudly told her I at least had a really good pair of shoes to run with, although a couple years old they weren't really used much yet and as good as new! "And how are you supposed to be able to finish a marathon if you haven't used your shoes the last couple of years" was her reply! Hmm, she had a point there - it's was time to get started!!</p>

<p>When it comes to motivation, Max definitely played his part by sending me some of his "<a href="http://ask.metafilter.com/37565/Training-for-a-marathon-in-one-month">research</a>".. Hmm.. did anyone mention knee injuries?! So, in conclusion; life won't be much fun if we always stick to what's smartest, now, would it?! Sometimes it now always about getting to the end of the road, it's HOW you get there!:)</p>

<p></p>

<p><strong>:: The training ::</strong></p>

<p>Max had already been training for two weeks, that's like 50% of my total training time, so I would have to work pretty hard to catch up! And Max was very well prepared indeed; maybe a bit too prepared someone might have said! With his brand new GPS running computer, new shoes and a lot of research of how to actually do this think in one month!</p>

<p>We both had the same goal, to finish without major injuries! We used, however, two pretty different strategies to get there. I was most concerned about the last part of the goal; "without major injuries". On the other hand, Max was most concerned about the first part; finishing. Meaning he stopped running as soon as he felt the pain come sneaking in order to be sure he didn't get injured before the marathon. Mine was, however, to constantly push it to prepare myself for what was about to hit me. So, here's what my plan was: the 3 first weeks I trained fairly hard. When it started hurting and became very uncomfortable running, but before it became directly painful, that's when I stopped running. After resting 1-2 days or whatever number of days it took for the pain the completely disappear I was ready for a new session. The remaining week I took it easy, giving my poor knees a chance to catch up and get ready for the big run! But at that point my knees didn't really hurt that much anymore.. I've also, after advise from my friend, practicing to run more softly, to minimize the "pressure" on my knees.</p>

<p>We were ready, both in undoubtably(?) good shape. It was a bit concerning that most of our trips was between 8-10 km only.. I had one run that lasted 18km before the knee started killing me, but still pretty far from 42km. That's when I made myself an ultimatum. If my knee started hurting badly during the marathon I would drop out, no discussion!</p>

<p></p>

<p><strong>:: The race ::</strong></p>

<p>After a long day of sightseeing the day before; getting up at 5:30 in the morning was a challenge itself. Eating plain wheat flakes with milk for breakfast didn't help much either. Especially without a spoon. But two hours later we were at the starting point in Marathons, almost ready to start. We felt pretty clueless how to prepare though. Do you warm up for a marathon? I mean, you'll be running slowly for 6 hours, what's the point of warming up!? But before we even figured out, I realized my starting number was gone, 20 minutes before the race began. Remembering reading that "you will not be able to start without your starting number" I kinda freaked out and ran back and forth looking for it. A few minutes after Max came towards me with my start number with a lot of footprints and dirt on it.. *puh*.. I have to admit my pulse rise quite a lot those few minutes.. so there I go, my warmup was complete!</p>

<p>10 minutes remaining, and we were preparing the gear! Max had of course his GPS with him, and I had my cellphone! We've promised people back home to give live updates during the race, so a cellphone was a requirement. How I was supposed to write text messages with the cellphone literally taped to my arm was another question. But more importantly; on my cellphone I had 4 hours of music - The Ultimate Marathon Mix! Legends say that faith can move mountains, but so can music!! Not literally, but music is the best motivation you can ever find! There are certain songs that just gets the rhythm and fill you with excitement! That's my 4 hours of marathon mix! That's what was going to keep me going! We were now ready for what was about to begin!</p>

<p>So, when it comes to the race itself.. what can I say?! It was 5 hours and 21 minutes of running! YES, I did complete the marathon! All the way! Was it hard, yes indeed it was, but I made it!</p>

<p>The biggest surprise; my stamina (or lack of it) wasn't an issue at all, I wasn't really breathing very heavily at all during the race. The pain, however, was just indescribable. In the beginning I kinda struggled to not run too fast as I knew that would probably kill my knees after a while if I did. So the first 25 kilometers went very smoothly, but the last 17, nah, not so smooth. The pain, sweet pain! Especially the last kilometers; I can remember how every step I made felt like my legs were going to fall anytime. Exhaustion, cramps, blisters, you name it! But my knees were OK! I actually had to stop and feel carefully because my muscles and feet hurt so much I had to be sure the muscle-pain didn't suppress any knee-pain! After 35 kilometers I just couldn't take it any more and had to start walking, which I did for the remainder of the race. At that point, though, I didn't really run much faster than I walked anyway, so I guess I didn't matter! I think I even walked passed a couple of guys still running.</p>

<p>But during the race you have a lot of spare time, and you start noticing the small things around you, the things that keeps you motivated. To me, seeing young children and entire families along the road cheering and shouting "bravo bravo bravo" was really inspiring. For quite some kilometers I ran together with an old man, he must have been 60-70 years or something. He was running steady as a rock up the hills. Amazing, who wouldn't get motivated by watching him. And when the going got touch, the text messages from Ngoc helped a lot, and not to talk about good old Roxette and Boney M singing loudly through my headphones. All together, it kept me going, one step at the time!</p>

<p>Coming into the stadium was just an amazing feeling, seeing Ngoc at the finish line cheering me forward was a priceless moment. The stadium wasn't really that crowed anymore, but it really felt like it was, people were screaming and cheering! At that precise moment all pain was forgotten and we all started running again. Though, 10 seconds later I was brutally reminded of the pain again. But it didn't matter! I was there! It was done! I was just about to finish the run of a lifetime!!</p>

<p></p>

<p><strong>:: Final thoughts ::</strong></p>

<p>The next day, going shopping in Athens, oh how I regret not bringing crutches!. And even worse, how I regret harassing Max for bringing crutches! I though it sounded like a bad idea when we left, kinda like jumping into the lifeboat in case the skip should start sinking.. but believe me it sounded like a good idea the day after! At that point it felt like all of my tendons was ripped halfway apart, which might not be far from the truth either.. But three days later, I was feeling a lot better. I was nearly able to walk normally and only one tendon is still hurting, but doesn't seem like something seriously. And today, one week later, I'm doing very fine and happy as ever!</p>

<p>So, I somewhat surprisingly reached my goals, and was I lucky it turned out this way, yes indeed I was! But one question still remains: WHY!? Pretty much all my friends asked me; why going through so much pain and lonely hours, running a high risk getting long-term injured?! I've never really been able to answer that question yet, it was definitely not for the money! Although there was a prize money the race cost me 80 euros.. and to put it that way; I wasn't running the best odds of winning. So, was it to be able to brag about it afterwards and impress people? Nah, not really. It's of course a nice story to tell, and.. hmm, maybe a little, but that wasn't my motivation when I joined it. What about pushing my limits and prove I could to it? Nope. I already know long-distance running is not my area, if I wanted to push my limits I'd chosen something I'm good at. Besides, I'm a programmer and computer engineer, if I were to prove something I'd use my brains, not my legs!</p>

<p>So, I still don't have a good answer! I shall admit I had a hard time finishing the marathon and that some parts of it wasn't much fun at all. But I guess it's all about the feeling I'm left with in the end! The satisfaction of achieving something great is one thing, but when I now, one week later, look back at the race, it wasn't that bad after all. The pain is gone, all I can remember now is exactly what I want to remember; the good times! Because that's what it really was all about, a great experience!</p>

<p>Pain is temporary, pride is forever!</p>]]>
    </content>
</entry>
<entry>
    <title>Motion sensor abuse now rampant</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/11/motion_sensor_abuse_now_rampan.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=32" title="Motion sensor abuse now rampant" />
    <id>tag:blog.medallia.com,2007://1.32</id>
    
    <published>2007-11-28T15:35:06Z</published>
    <updated>2007-11-28T16:21:12Z</updated>
    
    <summary>Cell phones are now being advertised with &quot;shake control&quot; (previously). Also, researchers at Glasgow University have a proof-of-concept video of a creative new use of the motion sensor: Shake the phone and hear &quot;your messages&quot; rattling around inside it....</summary>
    <author>
        <name>Erling Ellingsen</name>
        <uri>http://www.tykje.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>Cell phones are now being <a href="http://www.sonyericsson.com/cws/products/mobilephones/overview/w910i?cc=sg&lc=en">advertised</a> with "shake control" (<a href="http://www.therawfeed.com/2006/06/nokia-phone-sports-smackbook-pro.html">previously</a>).</p>

<p>Also, researchers <a href="http://www.dcs.gla.ac.uk/~jhw/shoogle/index.html">at Glasgow University</a> have a proof-of-concept video of a creative new use of the motion sensor: Shake the phone and hear "your messages" rattling around inside it.</p>

<p><object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/AWc-j4Xs5_w&rel=1"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/AWc-j4Xs5_w&rel=0" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object><br />
</p>]]>
        
    </content>
</entry>
<entry>
    <title>iPhone accelerometer source code</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/08/iphone_accelerometer_source_co.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=29" title="iPhone accelerometer source code" />
    <id>tag:blog.medallia.com,2007://1.29</id>
    
    <published>2007-08-28T18:51:50Z</published>
    <updated>2007-09-04T05:58:47Z</updated>
    
    <summary>Here&apos;s some code to initialize the accelerometer to run at full speed. Pass the desired sample rate (in Hz) to the initialize function. Go wild! [updated 9/3: fixed typo]...</summary>
    <author>
        <name>Erling Ellingsen</name>
        <uri>http://www.tykje.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>Here's some code to initialize the accelerometer to run at full speed. Pass the desired sample rate (in Hz) to the initialize function. Go wild!</p>

<p>[updated 9/3: fixed typo]</p>]]>
        <![CDATA[<pre>
#include &lt;IOKit/IOKitLib.h>
#include &lt;CoreFoundation/CoreFoundation.h>

<p><br />
typedef struct {} *IOHIDEventSystemRef;<br />
typedef struct {} *IOHIDEventRef;<br />
float IOHIDEventGetFloatValue(IOHIDEventRef ref, int param);</p>

<p>void handleHIDEvent(int a, int b, int c, IOHIDEventRef ptr) {<br />
  int type = IOHIDEventGetType(ptr);<br />
  if (type == 12) {<br />
    float x,y,z;<br />
    x = IOHIDEventGetFloatValue(ptr, 0xc0000);<br />
    y = IOHIDEventGetFloatValue(ptr, 0xc0001);<br />
    z = IOHIDEventGetFloatValue(ptr, 0xc0002);<br />
    // do whatever you need to do with the gravity<br />
    ballSetAccel(x, y);<br />
  }</p>

<p>}<br />
	  <br />
#define expect(x) if(!x) { printf("failed: %s\n", #x);  return; }</p>

<p>void initialize(int hz) {<br />
  mach_port_t master;<br />
  expect(0 == IOMasterPort(MACH_PORT_NULL, &master));</p>

<p>  int page = 0xff00, usage = 3;</p>

<p>  CFNumberRef nums[2];<br />
  CFStringRef keys[2];<br />
  keys[0] = CFStringCreateWithCString(0, "PrimaryUsagePage", 0);<br />
  keys[1] = CFStringCreateWithCString(0, "PrimaryUsage", 0);<br />
  nums[0] = CFNumberCreate(0, kCFNumberSInt32Type, &page);<br />
  nums[1] = CFNumberCreate(0, kCFNumberSInt32Type, &usage);<br />
  CFDictionaryRef dict = CFDictionaryCreate(0, (const void**)keys, (const void**)nums, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);<br />
  expect(dict);</p>

<p>  IOHIDEventSystemRef sys = (IOHIDEventSystemRef) IOHIDEventSystemCreate(0);<br />
  expect(sys);</p>

<p>  CFArrayRef srvs = (CFArrayRef)IOHIDEventSystemCopyMatchingServices(sys, dict, 0, 0, 0);<br />
  expect(CFArrayGetCount(srvs)==1);</p>

<p>  io_registry_entry_t serv = (io_registry_entry_t)CFArrayGetValueAtIndex(srvs, 0);<br />
  expect(serv);</p>

<p>  CFStringRef cs = CFStringCreateWithCString(0, "ReportInterval", 0);<br />
  int rv = 1000000/hz;<br />
  CFNumberRef cn = CFNumberCreate(0, kCFNumberSInt32Type, &rv);</p>

<p>  int res = IOHIDServiceSetProperty(serv, cs, cn);<br />
  expect(res == 1);</p>

<p>  res = IOHIDEventSystemOpen(sys, handleHIDEvent, 0, 0);<br />
  expect(res != 0);<br />
}</p>

</pre>]]>
    </content>
</entry>
<entry>
    <title>Fun with the iPhone accelerometer</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/08/fun_with_the_iphone_accelerome.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=28" title="Fun with the iPhone accelerometer" />
    <id>tag:blog.medallia.com,2007://1.28</id>
    
    <published>2007-08-28T06:02:04Z</published>
    <updated>2007-09-12T12:22:51Z</updated>
    
    <summary>Note (9/12): there is an application in the iBrickr PXL repository called &apos;Balls&apos; which links to this page. I have nothing to do with that app; it was created by Grudgnor over at the MacRumors forum. Those who have followed...</summary>
    <author>
        <name>Erling Ellingsen</name>
        <uri>http://www.tykje.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<blockquote><i>Note (9/12): there is an application in the iBrickr PXL repository called 'Balls' which links to this page. I have nothing to do with that app; it was created by Grudgnor over at the <a href="http://forums.macrumors.com/showthread.php?t=347289">MacRumors</a> forum.</i></blockquote>

<p>Those who have followed this blog will know that I like to like to play with unusual input methods (see my earlier posts on <a href="http://blog.medallia.com/2007/06/dyesight.html";multitouch</a>, <a href="http://blog.medallia.com/2006/06/shadowbook.html">ambient light sensors</a>, and the <a href="http://blog.medallia.com/2006/05/smacbook_pro.html">SmackBook</a>).</p>

<p>As it turns out, the iPhone has a built-in <a href="http://www.st.com/stonline/products/literature/ds/12726/lis302dl.htm">LIS302DL</a>, a tiny 3-axis accelerometer. While <a href="http://www.xeodesign.com/tilt.html">some</a> have attempted to use it from within the Safari browser (the Tilt game detects changes to the width of the browser page; it is basically used as a 1-bit input device), its potential is still somewhat untapped.</p>

<p><object width="425" height="353"><param name="movie" value="http://www.youtube.com/v/Wtcys_XFnRA&rel=0"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/Wtcys_XFnRA&rel=0" type="application/x-shockwave-flash" wmode="transparent" width="425" height="353"></embed></object></p>

<p>After a rather lengthy bout of reverse-engineering (I had barely touched ARM assembly before this), I finally figured out how to access the raw data from the accelerometer itself, as can be seen in the video above. Source code <strike>will be posted as soon as possible</strike> <a href="http://blog.medallia.com/2007/08/iphone_accelerometer_source_co.html">is posted here</a>. <i>(update: yes, it is possible to access the accelerometer directly through UIKit without this hack -- however, you'll be locked to the default sample rate, which is too slow for some of the fun stuff)</i></p>

<p>Straw poll: <a href="http://survey.medallia.com/?accel">What would you like to see on the iPhone?</a></p>]]>
        
    </content>
</entry>
<entry>
    <title>dyeSight $2 Multi-Touch Pad</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/06/dyesight.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=24" title="dyeSight $2 Multi-Touch Pad" />
    <id>tag:blog.medallia.com,2007://1.24</id>
    
    <published>2007-06-12T17:00:00Z</published>
    <updated>2007-06-12T20:31:50Z</updated>
    
    <summary>I guess most of the people reading this will have seen some of the multi-touch demos by Jeff Han, Apple and Tactiva. I wanted to play around with some ideas that required a multi-touch pad, but there aren&apos;t any devices...</summary>
    <author>
        <name>Erling Ellingsen</name>
        <uri>http://www.tykje.com/</uri>
    </author>
            <category term="OS X Hacks" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>I guess most of the people reading this will have seen some of the multi-touch demos by <a href="http://www.ted.com/talks/redirect?key=j_han">Jeff Han</a>, <a href="http://apple.com/iphone/">Apple</a> and <a href="http://tactiva.com/">Tactiva</a>. I wanted to play around with some ideas that required a multi-touch pad, but there aren't any devices available (Tactiva aren't shipping...)</p>

<p>Long story short, I made a simple one from a plastic bag, some dye and a camera:</p>

<p><object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/yzNh31q61gc"></param><param name="wmode" value=;transparent"></param><embed src="http://www.youtube.com/v/yzNh31q61gc" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object></p>]]>
        <![CDATA[<p>More information coming soon.</p>]]>
    </content>
</entry>
<entry>
    <title>jQuery Reference Widget</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/05/jquery_reference_widget.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=21" title="jQuery Reference Widget" />
    <id>tag:blog.medallia.com,2007://1.21</id>
    
    <published>2007-05-20T22:55:17Z</published>
    <updated>2007-08-10T17:58:33Z</updated>
    
    <summary>When Wolfgang Bartelme and the Prototype crew first launched their OSX widget, we jQuery folk tried not to covet. Try as we might though (truth be told) we wanted one too! Fast forward a few weeks later: I&apos;m on a...</summary>
    <author>
        <name>Ryan Dunphey</name>
        <uri>http://blog.medallia.com</uri>
    </author>
            <category term="widgets" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p><img alt="dash.jpg" src="http://blog.medallia.com/screen.gif" style="border:4px solid #eee; float:left; margin-right:8px; margin-bottom:5px;" />When <a href="http://www.bartelme.at/">Wolfgang Bartelme</a> and the <a href="http://www.prototypejs.org/">Prototype</a> crew first launched their OSX widget, we jQuery folk tried not to covet. Try as we might though (truth be told) we wanted one too!</p>

<p>Fast forward a few weeks later: I'm on a plane heading to our headquarters in Menlo Park. Eclipse (and a bunch of other technologies) are serving me our app via localhost--nice! ...that is, until I needed to reference those pesky $.ajax parameters!</p>

<p>With that in mind, and the remainder of the flight, I threw together a <a href="http://jqueryjs.googlecode.com/svn/trunk/tools/dashboard-widget/jQuery-dashboard-widget.v1.0.zip">jQuery reference widget</a>. It's been of value to us front-end developers at <a href="http://www.medallia.com">Medallia</a>, and now we're returning some love to the jQuery community with this public release.</p>

<p>The widget provides simple, searchable, offline access to the <a href="http://jquery.com/api">API</a>. More, we've provided the ability to search older APIs, as well as a few quick-links to online resources.</p>

<p>Per <a href="http://ejohn.org">Resig's</a> suggestion (and thanks John for all your help), we're releasing this with an <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a> and have made it available under <a href="http://jqueryjs.googlecode.com/svn/trunk/tools/dashboard-widget">version control</a>.</p>

<p>We hope you find it of value!</p>

<p><a href="http://jqueryjs.googlecode.com/svn/trunk/tools/dashboard-widget/jQuery-dashboard-widget.v1.0.zip" style="text-decoration: line-through">Download the widget, v1.0</a> (<a href="http://blog.medallia.com/jquery-widget.gif">View screenshots</a>)</p>

<p style="font-weight:bold;">I've updated the widget to the latest documentation  1.1.3.1.</p>  <a href="http://jqueryjs.googlecode.com/files/jQuery-dashboard-widget.v1.1.zip">Download version 1.1</a>]]>
        
    </content>
</entry>
<entry>
    <title>TopCoder Open Marathon: Robot Routing</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/05/topcoder_open_marathon_robot_r_1.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=19" title="TopCoder Open Marathon: Robot Routing" />
    <id>tag:blog.medallia.com,2007://1.19</id>
    
    <published>2007-05-03T00:00:00Z</published>
    <updated>2007-05-08T20:14:29Z</updated>
    
    <summary>Many developers here at Medallia have participated extensively in algorithmic coding competitions like the ACM World Championship of Programming and TopCoder Open. These are fast-paced and get the blood flowing, as you spend around an hour to solve a problem,...</summary>
    <author>
        <name>Øyvind Grotmol</name>
        
    </author>
            <category term="Code" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>Many developers here at Medallia have participated extensively in algorithmic coding competitions like the ACM World Championship of Programming and TopCoder Open. These are fast-paced and get the blood flowing, as you spend around an hour to solve a problem, and either your solution gives the correct answer for every single test case, or you score zero. This year, however, the <a href="http://www.topcoder.com/tc?module=Static&d1=tournaments&d2=tco07&d3=marathon&d4=description">TopCoder Open</a> added a new competition format, the marathon. Here you have typically one full week to work on a problem which is too hard to find the optimal solutions, but instead your solution is scored based on how well it fares compared to your competitors. With the possibility of all-paid travel to the finals in Las Vegas for the 8 best competitors and $15,000 to the winner, I decided to give this interesting new competition a shot.</p>

<p>There were 1249 registrants, which got narrowed down to 500, 200, 50, and finally 8 through four online rounds. In one problem you had to make an AI for a simplified version of poker, and in another you had to write a strategy for a lumberjack running around in a forest. It is however the fourth problem that is my topic, as here the competition gets really tough for those 8 finalist spots.</p>

<div style="width:220px; float:right;">
<a href="http://blog.medallia.com/routes.html" onclick="window.open('http://blog.medallia.com/routes.html','popup','width=593,height=374,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img alt="" src="http://blog.medallia.com/routes_thumb.png" width="198" height="125" align="right" /></a>
</div>

<p>The problem is about directing an army of up to several thousands robots as they go around in a warehouse delivering products, with the objective of completing all the assigned tasks as quickly as possible. Researchers have studied the general concept of multi-robot collaborative routing before, but it's much more fun to see what 50 good programmers can come up with in two weeks for this particular problem formulation.</p>

<p>Read the full entry to see a full explanation of my algorithms, the source code, and the results.<br />
</p>]]>
        <![CDATA[<p>A little more background on the problem: The warehouse is represented as a grid, which can be from 20x10 to 100x400 in size, so the solution will need to deal well with this dynamic range in board sizes. Around the warehouse are shelves, placed in a regular pattern, which are obstacles to the robots, and where the products are located. The products need to be dropped off at the left edge of the board.</p>

<p>If you really want the details, you can download my <a href="http://blog.medallia.com/RobotRouting.java">source code</a>. It's about 1000 lines of Java. No JavaDoc! I'm a bad guy :) While the code is clearly not production quality, it's far cleaner than what you'll find in the typical one-hour algorithmic contest problems. In this case, working on the problem over several days, I rewrote parts of the solution many times to try out different strategies, and then it helps quite a bit that the code isn't totally intertwined.</p>

<p>My analogy in dealing with this problem has been traffic planning. The robots are not allowed to crash into each other, and so one of the main challenges with the problem is moving the robots about in a manner that they don't hinder each other. With thousands of robots, the way to go is to introduce traffic rules. I consider as a lane each row or column without shelves. In a lane you can only go in one direction, and this direction will alternate between left and right in the rows, and up and down in the columns. This is what the picture illustrates (for a very small board).</p>

<p>Now, in order to route the robots given these traffic rules, I repeatedly need to find shortest paths from a robot's current location to its next destination, and that needs to be done really fast. With up to 40,000 locations on the map, we cannot precompute all the pairwise distances. However, we can precompute the pairwise distances between all intersections in the map, and now in order to find the distance from A to B you only need to add the distance from A to the next intersection, the distance from that intersection to the one before B, and the remaining distance to B.</p>

<p>I'm not a very strict traffic police :) I allow the traffic rules to be broken, as long as nobody's hurt. I.e. I will let a robot make a U-turn if it finds it opportune, given that no other robot is trying to move into that same spot.</p>

<p>I take one time step at a time, deciding on every single robot's action before moving on to the next time step, and so on until all the products have been delivered. Due to the intersections, there can be multiple robots bidding for the same spot at the same time, and those conflicts need to be resolved. I implemented a fairly simple recursive strategy where each robot just prioritises the different moves it can make, and tries performing it. If there's already another robot there, it asks that robot to move, and so on. This might sound like a potentially exponential run-time, but in fact it is linear in the number of robots. The reason is that if a robot is unable to move, then it won't be able to move the next time either, and if a robot moves, then it cannot move again that same time step, so either way the answer is "no" the second time a robot is asked to move.</p>

<p>One interesting aspect of this kind of competition format, is that you have to discover what works or not during the coding. Work progresses as a sequence of come up with ideas, implement, run, analyse the outcome, and find new or modified solutions for the issues that you come across. One thing I learned pretty fast is that traffic congestion spreads quickly. Once traffic is jammed in one place, robots will take long to get out of there, but more robots will pass by and get stuck, and you get a self-reinforcing process going. It is therefore essential to prevent congestion from arising in the first place. I did this by kicking robots that get stuck in an intersection, out of there, even if they don't want to. It's better to take a small hit in terms of a robot having to go longer, than risking a congestion which could stop the combined efforts of all the robots.</p>

<p>It proved impossible to avoid for all types of boards some level of congestion at the left edge of the board, since all the products are being dropped off there. That's why I deviated slightly from alternating the main directions of the lanes, by having both the leftmost lanes be upwards. This avoids robots trying to move down the very leftmost lane, where traffic is doomed to be blocked by robots dropping off robots, but instead have access to two lanes for moving upwards only.</p>

<div style="width:320px; float:right;">
<p align="right">
<a href="http://blog.medallia.com/visualizer.html" onclick="window.open('http://blog.medallia.com/visualizer.html','popup','width=997,height=1000,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false">
<img alt="visualizer" src="http://blog.medallia.com/visualizer_small.png" width="299" height="300" />
</a>
Visualizer provided by TopCoder
</p>
</div>

<p>In fact, the most effective measure for avoiding the congestion at the left edge of the board had to do with grouping together products that a robot is handling. The robots have capacity to carry a certain number of products at the same time. So the first step of my solution is to batch up all the tasks into assignments. I only allowed tasks to be grouped together that had the exact same drop-off point for the product. This effectively prevents robots from moving up or down the already congested left edge to deliver several products.</p>

<p>With this restriction, I could concentrate on each point on the left edge at a time while batching tasks, with typically a couple of hundred products to be delivered there. I begin with the task whose starting point is closest to the drop-off point, and consider each of the others in turn to find the one closest to this again, and so on until the capacity has been filled up. Then I start over again with the point closest to the drop-off of those remaining.</p>

<p>When I say "closest to the drop-off", I actually used two different definitions. One distance measure was the actual routing distance from the location of the product to the drop-off. The other one was simply the vertical distance between the pick-up and the drop-off, completely ignoring the horizontal distance. The idea of the first is obviously to reduce total routing distance, whereas the idea of the second is to avoid vertical movements at the congested left side of the board. I experienced that from test case to test case one or the other would be considerably better, but I could not immediately see what characterized the different situations. Looking at the parameters for the cases, I spotted a correlation with the number of robots available, but it was not enough to determine for sure which distance measure would be better. However, a little more analysis showed that the number of robots divided by the area of the board would give a clear separation. This lead to the only really magical constant in my program, namely that I switch distance function depending on whether the density is above or below 8.2%</p>

<p>After creating the batches of tasks, they also need to be assigned to the robots. The assignments that were the most unfortunate in the sense of having the longest route, are assigned first, in order for them not to delay the completion time. Each of these heaviest assignments in turn select the robot that is initially closest to them. The rest of the robots get to pick the assignments themselves, i.e. they pick the assignments that are closest to their initial position.</p>

<p>As the end of all the tasks is approaching, it gets increasingly important to help out the robots that seem to have the longest route left to go. This is done in two ways. One is that they're given first choice when resolving conflicting move requests. The other is that robots that finish their assignments, after there are no new assignments to pick, go through the robots that are still working and see if they can help them out by taking over some of their tasks.</p>

<p>The run time of my program varies between like a second and up to 40 to route all the robots through all the time steps, depending on the difficulty of the board. The time limit is 60 seconds per test case, which means I have plenty of time available. I used that to run the same algorithm several times, with different random seeds, and picking the best result. Typically there would be time enough for 20 rounds, and that improves the solutions somewhat since there's some level of variance.</p>

<p>I have here given a reasonably complete overview of all the features that are in the ultimate solution I ended up with. <br />
So how did it fare in the competition? Pretty well actually, I'm currently in 2nd place. It scored 30.37 points out of 35, which means that I'm on average like 15% behind the best answer from the aggregate of all the submitted solutions. The leader scored 32.72 points. The results are available <a href="http://www.topcoder.com/longcontest/?module=ViewStandings&rd=10757">here</a>.</p>

<p>So I am all set for Las Vegas! That will be really fun, and let's just hope I win more at the programming than I lose at poker, because I don't think that AI of mine from the previous round is going to help me much there. For the finals itself we get only 9 hours to solve the problem. It could turn out to be the most fun competition at TopCoder Open to watch onsite at the Mirage, as we'll probably be provided with a visualizer for our testing purposes and the spectators' amusement.<br />
</p>]]>
    </content>
</entry>
<entry>
    <title>Medallia is hiring</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/05/were_need_more_people.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=20" title="Medallia is hiring" />
    <id>tag:blog.medallia.com,2007://1.20</id>
    
    <published>2007-05-02T19:59:37Z</published>
    <updated>2007-05-02T23:52:29Z</updated>
    
    <summary>Medallia is growing rapidly and we need more people both at our Menlo Park, CA (Silicon Valley) and Oslo, Norway locations. For our User Experience team, we need a skilled front-end developer looking to push the boundaries of the browser...</summary>
    <author>
        <name>Rune Sandberg</name>
        <uri>http://www.medallia.com/</uri>
    </author>
            <category term="Jobs" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>Medallia is growing rapidly and we need more people both at our Menlo Park, CA (Silicon Valley) and Oslo, Norway locations. </p>

<p>For our User Experience team, we need a skilled front-end developer looking to push the boundaries of the browser in order to create unparalleled user experiences. To create elegant aesthetics we are looking for a visual designer that can make art scalable and appropriate in the context of web applications. </p>

<p>To join our world class engineering team, we are looking for a senior software developer with architect design skills and an ability to craft elegant code. And to give our engineers a run for their money, we do need someone that enjoys breaking things and finding vulnerabilities as an accomplished QA engineer.</p>

<p>To read more, head over to the <a href="http://blog.medallia.com/jobs/" title="Jobs at Medallia">jobs section</a></p>]]>
        
    </content>
</entry>
<entry>
    <title>Google Print &amp; Library Lookup Mashup</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/04/google_print_library_lookup_ma.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=18" title="Google Print &amp; Library Lookup Mashup" />
    <id>tag:blog.medallia.com,2007://1.18</id>
    
    <published>2007-04-09T01:28:04Z</published>
    <updated>2007-04-09T09:30:29Z</updated>
    
    <summary>Instantly know if that book you&apos;re glancing at on Google Print is available at the local library. Greasemonkey has been a great tool for creating efficiencies at work, and for hacking fun on the weekend. I like to support the...</summary>
    <author>
        <name>Al Nevarez</name>
        
    </author>
            <category term="Greasemonkey" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p><strong>Instantly know if that book you're glancing at on Google Print is available at the local library.</strong></p>

<div style="width:180px; float:right;">
<a href="http://blog.medallia.com/images/gprintmashup.html" onclick="window.open('http://blog.medallia.com/images/gprintmashup.html','popup','width=658,height=478,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img class="sm"src="http://blog.medallia.com/images/gprintmashup-thumb.png" width="150"  alt="" /></a></div>

<p><a href="https://addons.mozilla.org/en-US/firefox/addon/748">Greasemonkey</a> has been a great tool for creating efficiencies at work, and for hacking fun on the weekend.  I like to support the local libraries so I created this mashup of Google Print's book view and the San Francisco Peninsula Library system's book search. It immediately let's you know if the book you're paging through on Google Print is available in the library. Click on the  screenshot for a preview.  <a href="http://userscripts.org/scripts/show/8286">Get the script</a></p>

<p>The Greasemonkey Javascript puts a small yellow box in the corner of your Google Print book search. The box includes a book title and a link to the library system's search results. When clicked, a new browser tab is created containing the library's lookup page with the book's location and status.</p>

<p>The script also linkifies the library names on the latter page, to point to the library's street map, hours and phone page.</p>]]>
        <![CDATA[<p>This GM script acts on 2 completely separate pages. Should be relatively straightforward to alter for your own local library's book search API and map and hours.  </p>

<p>Install the script from here: <a href="http://userscripts.org/scripts/show/8286">http://userscripts.org/scripts/show/8286</a>, then simply goto <a href="http://books.google.com">http://books.google.com</a>, search for something then click through to a specific book.  If you don't have the Greasemonkey extension installed on your Firefox browser, do that first here: <a href="http://www.greasespot.net">http://www.greasespot.net</a>.</p>

<p>This hack was based on Junk Blocker's Peninsula Library System Amazon Lookup http://userscripts.org/scripts/show/1072,  which is based on... the Library Lookup script  http://userscripts.org/scripts/source/886</p>

<p>Al Nevarez<br />
Product Manager & weekend hacker</p>]]>
    </content>
</entry>
<entry>
    <title>Building Bridges</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/03/building_bridges.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=16" title="Building Bridges" />
    <id>tag:blog.medallia.com,2007://1.16</id>
    
    <published>2007-03-22T06:15:04Z</published>
    <updated>2007-03-22T06:06:13Z</updated>
    
    <summary>I recently read Dreaming in Code, a book by Scott Rosenberg which follows the development of Chandler, a software project started to design a revolutionary tool for personal information management. The recurring theme in the book is how hard software...</summary>
    <author>
        <name>Kristian Eide</name>
        
    </author>
            <category term="Code" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>I recently read <a href="http://www.dreamingincode.com/">Dreaming in Code</a>, a book by Scott Rosenberg which follows the development of <a href="http://chandler.osafoundation.org/">Chandler</a>, a software project started to design a revolutionary tool for personal information management. The recurring theme in the book is how hard software development has turned out to be, and why this is so surprising to most people.</p>

<p>Many have written their thoughts on this subject, and the comparison to building bridges is frequently made: if only we could build software the way we build bridges it would always be on time, on budget and of high quality.</p>

<p>I would argue, instead, that software development is <i>incredible easy</i>. It is so easy, in fact, that any 14-year-old with some spare time on his<a href="#14">*</a> hands can do it. No other profession is so readily available: anyone with a computer and some spare time can do it right from home.</p>

<p>Let me take you along on a small thought experiment: <b>what if building bridges was as easy as developing software</b> or in fact any kind of structure? What if, after writing down some specification on dimensions, material used and other necessary parameters you could press a button and said structure would magically appear out of thin air?</p>]]>
        <![CDATA[<p>Well, it stands to reason that a lot more people would try their hand at designing buildings. And any kind of building, be it a small house or a 500-story skyscraper, although the latter would of course require a lot more specification to get the details right. You could probably skimp on the details, however, by starting simple: a 2000-foot high rectangular box made of steel. Make it hollow (how wide should the walls be – I have no idea, so let’s guess at 2 inches), add some floors (4 inches thick is probably about right), stairs and the first version is ready! Press a button and there it is, standing magnificent and tall in front of you. Of course, two seconds later the whole thing comes crashing down. What, you mean it has to be stronger at the bottom than at the top to support its own weight? Well, there is always version 2.0…<br />
</p></p>

<p>I am sure you see where I am going with this: building high quality software is hard, just as designing a bridge or a skyscraper is hard. It requires proper training and experience, and just as some people are better suited to being construction workers rather than designers not all people should design large software systems.</p>

<p>The differences is that while it is intuitive that designing a skyscraper is hard, since most people have extensive experience manipulating objects in the real world, designing software is the exact opposite: constructs are taken out of what appears to be thin air and have little relation to physical objects. Since most people have no intuitive feel for how hard it is they assume it must be easy: after all, even 14-year-old kids can do it.</p>

<p>The result is predictable: after designing a few houses that come crashing down they finally make a few that keep standing (at least if you do not look at them for too long at a time). Great! All ready for heading over to monster.com and checking out some job descriptions…</p>

<p>Note that I am not in any way suggesting that the developers of Chandler are incompetent; in fact, designing software is hard even with a high-quality team. Probably the most significant reason it is so hard even under ideal circumstances is that every software project is like designing an almost completely new kind of structure: the design of physical objects is able to leverage the experience of previous designs to a much higher degree than what is possible in software. It is even more surprising, then, that people expect good results even under much less than ideal conditions.</p>

<p><a name="14" /><br />
* Unfortunately, due to the image problem our industry has, very few girls of that age dare venture here; that is a discussion for another time, however.</p>]]>
    </content>
</entry>
<entry>
    <title>A Guided Tour of Mercurial</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2007/02/a_guided_tour_of_mercurial.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=17" title="A Guided Tour of Mercurial" />
    <id>tag:blog.medallia.com,2007://1.17</id>
    
    <published>2007-02-25T04:32:00Z</published>
    <updated>2007-02-25T06:14:24Z</updated>
    
    <summary> Here at Medallia we have recently switched from Subversion to Mercurial for some of our projects. While both are very good tools for managing a source code tree there is a significant difference in the philosophy between the two...</summary>
    <author>
        <name>Kristian Eide</name>
        
    </author>
            <category term="Code" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>
Here at Medallia we have recently switched from <a href="http://subversion.tigris.org/">Subversion</a> to <a href="http://www.selenic.com/mercurial/">Mercurial</a> for some of our projects. While both are very good tools for managing a source code tree there is a significant difference in the philosophy between the two tools and the problems they are trying to solve. While I will not claim that Mercurial is perfect it has turned out to be a very significant improvement for us, mainly because of its support for tracking branches, which Subversion instead leaves in the (perhaps not so) capable hands of its users.

<p>
The following is a guide I wrote which we are using internally to get people up to speed on using Mercurial. While there are several other guides out there I have not found one which, in my opinion, explains well how to effectively work with named branches (probably because they were only relatively recently added to Mercurial). I also wanted a single document which explains everything necessary to start working in a clear and concise way. My hope is that this guide provides that.]]>
        <![CDATA[<p>
Mercurial's main distinguishing feature as compared to a more traditional SCM system like <a href="http://subversion.tigris.org">Subversion</a> is that it is fully distributed. In practice this means that there is no central repository, but rather every user has a complete copy of the repository, which is always part of a working copy. Thus, instead of committing changes to a central repository you instead commit changes to the local repository and only later transfer (push) these changes over the network to a public place.
</p>

<h3><a name="Getting_the_repository"></a> Getting the repository </h3>

<p>
Getting a copy of the repository, or <i>cloning</i> it as it is called, is done with the clone command:

<pre>
hg clone ssh://server//hg/repos my-repos
</pre>

<p>
This will create a new directory, my-repos, that has a complete copy of the 'repos' repository.
</p>

<h3><a name="Branches"></a> Branches </h3>

<p>
In Mercurial everything is a branch, that is, every time you commit something you either create or extend a branch. The repository can be visualized as a graph where the nodes are the individual revisions (i.e. a snapshot of all the files in the repository at a certain point in time) and the links between them the changes that have to be done to get from one node to the other.
</p>

<p>
Every node (except the very first of course) will have at least one parent, and some, where a <i>merge</i> was done, will have two. A working copy will always correspond to a specific node (revision) and when you commit your changes a new node is created which has that node as its parent. A <i>head</i> is a node that has no children (think of <a href="http://en.wikipedia.org/wiki/Image:Cap037-1.jpg" target="_top">Medusa</a>).
</p>

<p>
For example, let us imagine that both Alice and Bob have cloned a repository from a public server and their working directories correspond to revision 1. They both make some changes and commit their files to their local repositories. Alice's pushes her changes to the public server first and sometime later Bob tries to do the same. Mercurial now tells him that doing so would create an extra head in the repository and asks if perhaps he instead meant to <i>merge</i> his changes.
</p>

<p>
That was indeed what Bob wanted and he first does a pull from the public repository. His local repository how has three nodes; 1, which both he and Alice started working from, 2, which contains Bob's changes, and 3, which has Alice's changes. Both 2 and 3 have 1 as their parent and they have no children, thus the repository has two heads.
</p>

<p>
What Bob wants to do is merge his changes with Alice's, so he types:
</p>

<pre>
hg merge 3
</pre>

<p>
What this means is to merge the changes from revision 3 with the revision in the working directory, which in Bob's case corresponds to revision 2. He then types:
</p>

<pre>
hg commit -m &#39;merge&#39;
</pre>

<p>
In this commit a new node (revision 4) is created which has both 2 and 3 as its parents. Bob can now push this revision to the public repository, and when Alice later pulls she will get revision 4 which has Bob's changes.
</p>

<h3><a name="Named_branches"></a> Named branches </h3>

<p>
Mercurial also has the concept of named branches, which is basically just a special tag that is applied to a revision when it is committed. By typing:
</p>

<pre>
hg branch my-branch
</pre>

<p>
you tell Mercurial to attach the branch tag <i>my-branch</i> to any commits that you make (type 'hg branch' to see which branch tag you are currently using). You can get a list of all the branch tags in the repository by typing:
</p>

<pre>
hg branches
</pre>

<p>
Mercurial will list all the branch tags and also the highest revision number of each branch, also called the <i>tip</i> of the branch. This is important: it is the revision that Mercurial will use if you tell it to e.g. update your working directory to a given branch or to push a given branch, both of which you will be doing frequently.
</p>

<p>
Let us enlist Alice and Bob again to give us an example. As before, they both have cloned a public repository and are at revision 1. Alice types 'hg branch alice' while Bob types 'hg branch bob'.  They both make some changes and commit them to their local repositories. Alice pushes her changes, and after a while Bob tries to do the same. As before, Mercurial asks if he instead meant to merge his changes, so he does a pull from the public repository.
</p>

<p>
His repository now has three revisions, but revision 2 has the branch tag 'bob' while revision 3 has 'alice'. Since Bob wants to continue working independently of Alice he does not want to merge; instead he uses the '-f' switch when pushing to tell Mercurial that he really wants to create a new branch. The public repository now has two heads, and when Alice does a pull she can see Bob's new branch.
</p>

<h3><a name="Collaborating_on_branches"></a> Collaborating on branches </h3>

<p>
Let us continue the above example: Bob has his own branch that he is working on, but since he is a nice guy he also wants to help Alice with an update she requested. Since his own branch is in a bit of a mess at the moment he does not want to put any of that in Alice's very tidy branch. He makes sure he has committed all his own changes (i.e. typing 'hg status' does not print anything) and then types:
</p>

<pre>
hg up -C alice
</pre>

<p>
This changes his working directory over to Alice's branch; all his own changes are removed and his working directory is now an exact copy of the tip of Alice's branch. He can now happily do the requested change and then commit (Mercurial changes the active branch tag automatically, but you can type 'hg branch' to verify that it says alice). To push this so Alice can get his update Bob types:
</p>

<pre>
hg push -r alice
</pre>

<p>
Now only the changes to the alice branch are pushed to the public server. The next time Alice does a pull she will get Bob's update. Let us image that she had continued development in parallel with Bob and had committed several changes to her local repository, without pushing them to the public server. Let us say that the last version she pushed was 10 and that this is the revision that Bob made his changes to. Her local repository will now have a revision X which has 10 as its parent and contains Bob's changes; she also has revisions 11, 12 and 13 which are her own changes and their also inherit from 10. To integrate Bob's changes Alice first makes sure she has committed all her local changes and then types:
</p>

<pre>
hg merge X
hg commit -m &#39;merge in change from Bob&#39;
</pre>

<p>
Note that if there were any conflicts as a result of the 'hg merge' command Alice would have to resolve those before typing the commit command (more on this later).
</p>

<p>
Alice now has a new revision, 14, which has 13 and X as its parents. Note that I used X here instead of a revision number for Bob's change; the reason for this is explained in the next section.
</p>

<p>
<b>First I would like to mention a few words of caution</b>. A consequence of the way named branches work in Mercurial, which might be surprising at first, is that while normally each named branch that is still active will also be a head in the repository, when you merge changes from one named branch into another this is no longer the case. Only the branch which you merged into remains a head, and when you push the merge revision Mercurial will print '(-1 heads)'. If someone else later wants to continue development on the other branch they will have to use the '-f' flag to tell Mercurial to "reopen" the branch and it will print '(+1 heads)'.
</p>

<p>
Normally the fact that a head is removed when you merge two named branches is not a problem, however, there is one case where care needs to be taken. If, after pushing a branch merge revision, someone else commits a revision on the branch which is no longer a head, and the parent of that revision is before the revision which got merged then some revisions are now <b>only found on the other branch</b>. That is, some revisions which were originally committed on branch 'foo' are now only present on the branch 'bar' if 'foo' were merged into 'bar'. Thus, when pushing a revision which would create a new head one should always check if it is necessary to do a merge as well.
</p>

<h3><a name="Revision_numbers"></a> Revision numbers </h3>

<p>
Since Mercurial is a distributed system there is no coordination of how revision numbers are assigned; this means that both Alice and Bob can have a revision 2 that are actually very different; the reason Mercurial uses these simple revision numbers at all is just to save you some typing. However, always remember that they are local to a repository and that when talking to someone else you have to use the <i>revision id</i>. This is the hex string that Mercurial always prints next to the revision number, e.g. 42:<b>a416abc8f0e1</b>. This id is a 'fingerprint' of all the changes in a revision and people can thus come up with the same id for the same set of changes without any communication between them.
</p>

<p>
The revision id can always be used instead of the revision number, thus you can write:
</p>

<pre>
hg up 42
hg up a416abc8f0e1
</pre>

<p>
And both will do the same thing, however, only the last line is guaranteed to do the same thing no matter what repository you write it in.
</p>

<h3><a name="Named_branches_and_updating_your"></a> Named branches and updating your working copy </h3>

<p>
A word of caution about updating your working copy from a repository containing named branches: always give the name of the branch you are working with when updating. E.g. always write:
</p>

<pre>
hg up my-branch
</pre>

<p>
Omitting 'my-branch' in the above command will give you a warning about the update spanning branches, and ask you to either do a merge or add the '-C' switch if you really want to switch branches. However, if you do this any uncommitted changes in your working directory will be removed, so beware!
</p>

<p>
You can use the following command to do a 'safe' branch switch, i.e. it will automatically use the '-C' switch only if it is safe to do so (i.e. no uncommitted local changes):
</p>

<pre>
hg status &#124; grep . &#124;&#124; hg up -C &#34;$&#64;&#34;
</pre>

<p>
Also remember to specify the branch when pushing to a remote repository, although Mercurial will warn you if the push would create a new head in that repository.
</p>

<h3><a name="Merge_conflicts"></a> Merge conflicts </h3>

<p>
When you use the 'hg merge' command Mercurial will do its best to integrate the changes, however, if two people make changes to the same lines of code then Mercurial cannot figure out how to handle this and will instead kindly ask you to have a look. There are several tools that will help you with dealing with conflicts and Mercurial can be configured to use the tool you want; if no such tool is installed both versions of the conflict will be inserted in the file with special marker lines around them.
</p>

<p>
Under OS X Mercurial will use FileMerge.app if Xcode is installed; this highly recommended. On Windows, <a href="http://kdiff3.sourceforge.net/">KDiff3</a> can be used.
</p>

<h3><a name="Looking_at_changes"></a> Looking at changes </h3>

<p>
Let us say you are going to do a code review and have been told that revision a416abc8f0e1 has the changes in question. Simply type:
</p>

<pre>
hg export a416abc8f0e1
</pre>

<p>
Mercurial will print all the changes that happened in that revision.
</p>

<h3><a name="Adding_and_removing_files"></a> Adding and removing files </h3>

<p>
There are two separate issues here: the first is renaming / moving files, in which case you should use 'hg rename' or its alias 'hg mv'. Failure to do so means that Mercurial does not know that the new file is actually just the old file in a new place, and it <b>will</b> create unpleasant merge conflicts. Another option is to use the '-s' flag to addremove, e.g. write:
</p>

<pre>
hg addremove -s 50
</pre>

<p>
Mercurial will now try to detect if any new files are actually an old file that was moved.
</p>

<p>
The other case is where you actually deleted old files and then added unrelated new ones. In this case you can either use 'hg remove' and 'hg add' respectively, or the 'hg addremove' command which will automatically mark all missing files as deleted and all new files as added. Do make sure that you have actually deleted all the files you want to delete and do not have any spare files you do not want to check in lying around in your repository (use 'hg status' for this) before using this command.
</p>

<p>
In any case it is always a good idea to use the '-n' flag first, which tells Mercurial to only print the changes it would otherwise perform so you can verify them.
</p>]]>
    </content>
</entry>
<entry>
    <title>Gafter&apos;s talk on closures for Java</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2006/12/gafter_on_closures.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=15" title="Gafter's talk on closures for Java" />
    <id>tag:blog.medallia.com,2006://1.15</id>
    
    <published>2006-12-19T15:17:22Z</published>
    <updated>2006-12-19T15:21:49Z</updated>
    
    <summary>I thought it would be worth noting that Neal Gafter&apos;s talk on the closures proposal for Java is now online. Enjoy....</summary>
    <author>
        <name>Erling Ellingsen</name>
        <uri>http://www.tykje.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>I thought it would be worth noting that <a href="http://gafter.blogspot.com/">Neal Gafter</a>'s <a href="http://www.bejug.org/confluenceBeJUG/display/PARLEYS/Closures+for+Java">talk on the closures proposal for Java</a> is now online. Enjoy.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Aspirin for headache</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2006/11/aspirin_for_headache_1.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=14" title="Aspirin for headache" />
    <id>tag:blog.medallia.com,2006://1.14</id>
    
    <published>2006-11-08T17:06:41Z</published>
    <updated>2006-11-19T00:31:22Z</updated>
    
    <summary>A while ago a big pharmaceutical company wanted to expand their business to the Middle East since their marked research showed that there was a large untapped marked there for headache medication. The only problem was that since many people...</summary>
    <author>
        <name>Kristian Eide</name>
        
    </author>
            <category term="Code" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>A while ago a big pharmaceutical company wanted to expand their business to the Middle East since their marked research showed that there was a large untapped marked there for headache medication. The only problem was that since many people there did not know how to read their normal advertising would not be effective, but then someone came up with the idea of using this visual ad:</p>

<div style="text-align:center" >
<img style="margin:0 auto" alt="Aspirin reversed" src="http://blog.medallia.com/images/kristian_aspirin_reversed.gif" width="626" height="210" />
</div>

<p>They thought this was a brilliant idea and went ahead, putting it up on numerous big billboards. After a few weeks the sales were still very slow, however, and they could not figure out why, until after asking a few people why they were not interested it dawned on them.</p>]]>
        <![CDATA[<p>Arabic is read from right to left:</p>

<div style="text-align:center" >
<img style="margin:0 auto" alt="Aspirin normal" src="http://blog.medallia.com/images/kristian_aspirin_normal.gif" width="632" height="210" />
</div>

<p>I was recently given the task of writing a component for sending out email. Now, JavaMail works pretty well, but you still need to have a mail queue, delivery threads, error detection and retrying. Thinking that this surly must be a solved problem I went in search for a library with an implementation I could use and came across one called Aspirin, an embeddable java smtp server. The author wrote that it was so named because JavaMail is such a headache to use and Aspirin eases the pain by making it easy. Great I thought; my headache is solved!</p>

<p>Oh boy was I in for a surprise.</p>

<p>After integrating Aspirin into my email component I wrote a test case to make sure everything worked nicely, and mail added to Aspirin’s mail queue was indeed delivered. After doing some stress testing with multiple threads, however, I suddenly I got this:</p>

<p><code>java.util.ConcurrentModificationException</code></p>

<p>This was of course bad news; a mail queue better be thread safe! I dove into the Aspirin source code to see what was going on, and it did not take long to find the smoking gun: the mail queue was implemented as a Vector; I can only guess it was chosen since it is indeed synchronized. However, email was retrieved from the queue in a (synchronized) method which first sorted the vector in place (sorting the queue for each retrieval, using time <i>O(n<sup>2</sup> lg n)</i> to empty the queue) and then iterated over it using an Iterator; it is explicitly stated in the Javadoc for Vector that this is not thread safe without external synchronization, which I guess the author hoped making the method synchronized would achieve. Clearly the author has no clue as to how synchronization in Java works. Did I mention that after the first time you add mail to the queue you must wait a bit, otherwise you get an <code>IllegalThreadStateException</code>?</p>

<p>After reading a bit more of the source code it soon became clear that this library should not be used for anything other than testing or demo purposes; there are many more smoking guns and gotchas hidden in there, and I will not even bother listing the ones I found.</p>

<p>I instead ended up writing my own mail queue wrapper around JavaMail, which is completely thread safe, has <i>O(lg n)</i> add and retrieval time and gives a lot more control over what happens to emails after they are added to the queue (I want to keep track of the status of each mail, so that in case the JVM is suddenly stopped I do not lose any mail).</p>

<p>The moral of the story is that when you use external libraries you should spend a few minutes examining the source code, and if it looks suspect do not use it. You will save yourself a big headache.</p>]]>
    </content>
</entry>
<entry>
    <title>Lies, Damn Lies, and Statistics</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2006/11/lies_damn_lies_and_statistics_1.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.medallia.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=13" title="Lies, Damn Lies, and Statistics" />
    <id>tag:blog.medallia.com,2006://1.13</id>
    
    <published>2006-11-02T17:55:16Z</published>
    <updated>2006-11-19T00:31:54Z</updated>
    
    <summary>Medallia has, as part of its product portfolio, an advanced data analysis tool which is the main interface we provide our customers for looking at the data we collect for them. This tool is a web-based application and can answer...</summary>
    <author>
        <name>Kristian Eide</name>
        
    </author>
            <category term="Code" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>Medallia has, as part of its product portfolio, an advanced data analysis tool which is the main interface we provide our customers for looking at the data we collect for them. This tool is a web-based application and can answer questions such as “show me, for each question asked, the percentage of females who gave me a top 10% score grouped by income level for the past quarter, and show the percent change since the same quarter of last year” in less than a second even when the number of surveys are in the millions. “Yeah, yeah, am I sure it makes coffee as well” you are probably thinking, but this is actually important for what I am about to explain.</p>

<p>Since we provide a web application to our customers that we host ourselves we are naturally interested in how it is being used. A while ago one of our account managers asked me to compile a report for her on how many times people from a specific client had logged in over the last week, and I quickly realized that this would not be the last such request. As much as I enjoy grepping through logfiles (or even writing a small perl script to do it for me) I would much rather spend my time developing new features, so then I got an idea. Since we already have an advanced reporting application that churns through millions of records in less than a second while making coffee, why not try to use it to do our usage statistics as well? How much work would it take? Not much as it turns out!</p>]]>
        <![CDATA[<p>First I had to decide what kind of statistics I wanted to collect, and came up with this list:</p>

<ul>
<li>Web browser</li>
<li>Operating system</li>
<li>Screen resolution</li>
<li>Color Depth</li>
<li>SSL used</li>
<li>Cookie support</li>
<li>JavaScript support</li>
<li>Flash version</li>
<li>IP address logged in from</li>
<li>Number of views for each page</li>
<li>Average and max time looked at each page</li>
<li>Average and max time to generate each page</li>
</ul>

<p>So how much work did it actually take? First I had to write a User-Agent parser since I could not find one, which required about 85 lines plus 50 lines for the unit test (which is basically just a list of lots of User-Agent strings taken from Wikipedia). The JavaScript for determining screen resolution, color depth and Flash version came out to about 15 lines, while the rest of the information was already available. But how much code did it take to integrate all this into the reporting application? About 200 lines – the whole thing took about half a day for the initial version (I later added asynchronous committing to the database since the user should not have to wait for this, which added about 100 lines).</p>

<p>So now I can produce reports such as:</p>

<ul>
<li>the number of logins using Firefox 1.5 or higher grouped by the percentage using each operating system over the last 6 months, and the change since the 6 months before that</li>
<li>a graphical view of the browser distribution grouped by month over the last 12 months</li>
<li>Who spent at least one minute looking at the Profiler report last week</li>
<li>How much the different parts of our application are being used, and which type of user (e.g. corporate, region manager, individual property manager) are using the different reports</li>
</ul>

<p>These reports can be quite useful in making business decisions. For example, does enough of our user base have Flash enabled that we could use it to play back voice files, or is a browser used enough that we need to have it be one of the browsers we QA our site with?</p>

<p>I can also produce nice graphs like this one, which shows the total number of logins (y-axis scale has been omitted to protect the innocent):</p>

<div style="text-align:center" >
<img style="margin:0 auto" alt="medallia-logins-graph.png" src="http://blog.medallia.com/images/medallia-logins-graph.png" width="485" height="321" />
</div>

<p>At the start of this post I mentioned that the system is designed to handle millions of records while still doing real-time calculations, and this quickly becomes important since we can expect thousands or even tens of thousands of logins as we scale the system up. Fortunately, even 50.000 logins per month over the next 5 years is only a total of 3m logins, so scaling should not be an issue.</p>

<p>So how come that a reporting application designed for people taking surveys could be made to do all kinds of statistics on login sessions in half a day with only a few hundred lines of code? Good abstractions and reusable code. We already had a unit test which created some questions, created the possible answers, created a record with some made-up answers, injected it into the OLAP engine, did some calculations and finally checked the result. Most of the time was thus spend on actually collecting the required information, and it was straight forward to adapt the code from the unit test to create the data structures on-the-fly and injecting the data. The reporting application itself is completely configurable (since we need to customize it for each industry vertical as well as different clients), and now the account managers can simply look at the usage statistics for themselves. Actually, even our clients can use it, thus offloading our account managers. And I had much more fun than I would have had tweaking regular expressions in perl (fun as that is).</p>]]>
    </content>
</entry>

</feed> 

