<?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,2011://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>2011-06-13T20:01:58Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.2</generator>
 
<entry>
    <title>Medallia Hackathon: Celebrating Innovation</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2011/06/first_medallia_hackathon.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=45" title="Medallia Hackathon: Celebrating Innovation" />
    <id>tag:blog.medallia.com,2011://1.45</id>
    
    <published>2011-06-13T16:37:27Z</published>
    <updated>2011-06-13T20:01:58Z</updated>
    
    <summary><![CDATA[Over the years at Medallia, we've been able to organically cultivate innovation. No one needs permission to think outside the box; it's in our blood. So when we recently held our first Hackathon&mdash;ten years into the company's existence&mdash;it wasn't so much to encourage innovation, but rather to celebrate the very thing we've always done.

We added a twist to our Hackathon (which we'll get to shortly), but traditionally Hackathons are engineering-centric events: 24 sleep-deprived hours in which coders bang out the ones and zeros, and in the end some small glorious innovation transpires.

We hacked on lots of things, but a couple to note:]]></summary>
    <author>
        <name>Medallia</name>
        <uri>http://blog.medallia.com</uri>
    </author>
            <category term="Hackathons" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>Over the years at Medallia, we've been able to organically cultivate innovation. No one needs permission to think outside the box; it's in our blood. So when we recently held our first Hackathon&mdash;ten years into the company's existence&mdash;it wasn't so much to encourage innovation, but rather to celebrate the very thing we've always done.</p>

<p>We added a twist to our Hackathon (which we'll get to shortly), but traditionally Hackathons are engineering-centric events: 24 sleep-deprived hours in which coders bang out the ones and zeros, and in the end some small glorious innovation transpires.</p>

<p>We hacked on lots of things, but a couple to note:</p>

<h3>We Hacked Mobile</h3>

<p>We have a reputation for our <a href="http://www.medallia.com/products/mobile/iphone">industry-leading mobile apps</a>, and during the Hackathon we took the opportunity to expand into push notifications and position our platform to better support HTML5. This of course made our mobile initiative more buzzword compliant, but more important, it made our tools more accessible to a wider audience.</p>

<p style="text-align:center"><img src="http://www.medallia.com/posterous/hackathon-mobile.png" /></p>

<h3>We Hacked Maps</h3>

<p>Perhaps the highlight of the day was the maps hack. As we've grown, it's been difficult to keep up with all the new employees and where they sit. We'd been managing this with an (albeit impressive) shared spreadsheet. But at our Hackathon, some engineers bested the spreadsheet by integrating Google Maps with our employee Wiki. (Click on the screenshot to get an idea of why we're so excited about it!)</p>

<p style="text-align:center"><a href="http://www.medallia.com/posterous/map_large.png"  style="border:none; text-decoration:none;"><img src="http://www.medallia.com/posterous/map_small.png" style="border:none;" /></a></p>

<h3>We Hacked Rooms</h3>

<p>Yup, the twist was we incorporated the entire company, from accountants to executives&mdash;everyone hacked on something, and some hacked rooms. We've got nearly as many conference rooms as there are countries, and if we have an employee contingent from a country, it earns a room name. (Make sense?) Anyway, "Norway" got hacked with minimalistic Scandinavian furniture, painted landscapes and silhouettes of skiers, and, most important, an electric fireplace to make all the other conference rooms jealous.</p>

<p style="text-align:center"><img src="http://www.medallia.com/posterous/norway_small.png" /></p>

<h3>A Great Success</h3>

<p>The whole event was a blast. And although you can't superficially create innovation, Hackathons allow a unique opportunity to celebrate it. Getting the whole company on board was a huge success, and we're looking forward to our next Hackathon soon.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Automated Functional Testing at Medallia</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2010/08/automated_functional_testing_a_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=43" title="Automated Functional Testing at Medallia" />
    <id>tag:blog.medallia.com,2010://1.43</id>
    
    <published>2010-08-06T01:03:39Z</published>
    <updated>2010-08-06T03:22:41Z</updated>
    
    <summary> Motivation Functional Testing is a key component in any development process. Its main objective is to identify potential issues before they reach production and negatively impact eventual users. These tests tend to be time consuming, and are often described...</summary>
    <author>
        <name>Fernando Martin</name>
        <uri>http://blog.medallia.com</uri>
    </author>
            <category term="Code" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<h2> Motivation </h2>

<p><i>Functional Testing</i> is a key component in any development process. Its main objective is to identify potential issues before they reach production and negatively impact eventual users. These tests tend to be time consuming, and are often described as the ‘bottleneck’ in the development cycle. </p>

<p>At this point, <i>Automated Functional Tests</i> kick in. Several tools are available to generate these UI tests (here at <i>Medallia</i> we use <i>Selenium</i> and <i>HtmlUnit</i>), but in general the test suites based on these frameworks rely entirely on the UI, making them unnecessarily time consuming and flaky. A particular suite that is aimed at testing a specific functionality requires a number of preconditions that are usually fulfilled by creating the various necessary components through the UI. As a result, a test that has the goal of verifying some small case ends up having a lot of boiling code that takes quite some time to execute, and also might fail due to inherent flakiness of the UI test. </p>]]>
        <![CDATA[<h3> Data Sharing... don't! </h3>

<p>One solution might be to have a common data set that all tests can access: a common starting point for all the suites. But that has another inherent problem that one prefers not to face: data dependency. Now you have a system where one test might interfere with others, and trust me, if there is one key feature that has to be maintained for the success of any testing framework <i>-both at unit and functional level-</i> it’s the independence of tests.</p>

<h2>Our Solution at <i>Medallia</i></h2>

<p>As I explained before, we wanted a system that was reliable and fast, where we apply UI testing only to the portions of the test that we WANT to actually verify. Also, we wanted test independence so developers could focus on testing their feature and not worry about the rest.  What’s more, with test independence it is possible to run all the tests in parallel, reducing the length of each test cycle. Additionally, we wanted our framework to be easily extendable, where all the components are reusable, in order to minimize the time needed to create a new test.</p>

<p>In order to achieve these objectives, we came up with an automated framework that is based on three main modules:<br />
<ul><li><b>Components:</b> A "bean" that represents any entity of the application. For example, the component <i>User</i> that contains a <i>name</i> and a <i>password</i>.</li><br />
<li> <b>Commands:</b> A method that performs an action using the components. For example, <i>createUser(User)</i> or <i>deleteUser(User)</i> </li><br />
<li> <b>Facades:</b> An interface that groups the commands by functionality. Following the same example, a <i>UserFacade</i> should contain the commands <i>createUser</i> and <i>deleteUser(User)</i></li><br />
</ul></p>

<p>Then we provided different “implementations” of those facades and finally we created a system that picks the right implementation of the specific functionality for each test. In addition, we built a basic QA Api that is able to receive different commands and create data in the backend (in our case it is mainly calling the create method of the different components we have in the production system, but it could be done by opening a DB connection, or even better, you could use the production API if your system has one).</p>

<h3> Simple Example </h3>

<p>Let’s illustrate the basic behavior with an example:</p>

<p>We have our <i>“User”</i> interface that defines two methods:</p>

<p><img alt="UserFacade.png" src="http://blog.medallia.com/UserFacade.png" width="264" height="97" /></p>

<p>Then we have two different implementations of that facade:</p>

<p><img alt="SeleniumUserFacade2.png" src="http://blog.medallia.com/SeleniumUserFacade2.png" width="453" height="196" /></p>

<p><img alt="QAApiUserFacade2.png" src="http://blog.medallia.com/QAApiUserFacade2.png" width="424" height="198" /></p>

<p>In the actual framework, each <i>ImplementationFacade</i> does not directly implements the <i>Facade</i>, so there is no need to implement on each <i>ImplementationFacade</i> all the commands defined in the <i>Facade</i>.</p>

<p>Now there is a mechanism that runs an algorithm every time a test calls a method of the interface, to check which implementations have that method available, and will then execute the implementation that has the highest priority (lowest number). You can also force a command to run under a specific implementation.</p>

<p>For example:</p>

<p><img alt="ExampleTest.png" src="http://blog.medallia.com/ExampleTest.png" width="344" height="387" /></p>

<p>These two tests end up doing the same thing: they both create one user and then deletes it. The difference is that the first one is going to create the user through the UI and then delete the user through the QA API, while the second test does the opposite. </p>

<p>This approach gives us several advantages:<br />
<ul><li>We only do the UI testing of the particular logic component that we want to test (in this example all the assertions that the component was successfully created are missing, but it is quite simple to code those assertions with Selenium).</li><br />
<li>Our tests are not tightly coupled with a specific implementation. This offers us two main advantages:<br />
<ul><li>In the future, if we decide to use another tool (rather than Selenium), we can simply create a new implementation using that tool and almost no change has to be made to the tests)</li><br />
<li>If at some point we have, for example, a production API that allows us to handle the creation of the components, we simply have to create a new implementation of a facade, assign it a higher priority and then all of our tests will begin using that implementation with no change at all!</li></ul></li><br />
<li>We have a fast and reliable way of creating all the components needed in the preconditions without going through the UI. If a test needs to have five different users, simply call those ‘create methods’, then enable UI testing, and you can test your functionality from there.</li><br />
<li>The commands are completely reusable, once a method is created, it is automatically available for any other test.</li><br />
<li>You can have one command that will create a basic entity from scratch (for example a company with <i>X</i> number of users, <i>Y</i> locations around the globe, etc.), so that all the tests can call that command at the beginning and have a fresh new entity, that no other test uses, achieving data independence.</li></ul></p>

<p>We are still working in the final details and we hope that at one point we will be able to open the code of the framework in order to share it with the community.</p>]]>
    </content>
</entry>
<entry>
    <title>Continuous integration at Medallia</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2010/06/continuous_integration_at_meda.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=42" title="Continuous integration at Medallia" />
    <id>tag:blog.medallia.com,2010://1.42</id>
    
    <published>2010-06-16T00:22:04Z</published>
    <updated>2010-06-17T07:40:22Z</updated>
    
    <summary>Continuous integration is an important tool for finding issues early and is especially useful in team environments. Here at Medallia, we have built our own continuous integration system which automatically builds all our code, runs the test suite and presents...</summary>
    <author>
        <name>Kristian Eide</name>
        
    </author>
            <category term="Code" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>Continuous integration is an important tool for finding issues early and is especially useful in team environments. Here at Medallia, we have built our own continuous integration system which automatically builds all our code, runs the test suite and presents the results in a nice UI.</p>

<p>About 3 years ago we switched from Subversion to <a href="http://mercurial.selenic.com/">Mercurial</a> which allows us to improve our workflow by keeping all features on separate branches until they are ready to be merged. Each release gets its own integration branch, and these are numbered sequentially; our current release branch is called <i>e55</i> and the next will be <i>e56</i>. Once a feature has been developed and tested, it is merged to the next release branch.</p>]]>
        <![CDATA[<p>It can be hard to visualize a Mercurial repository with many branches, and thus we have developed a simple web application which helps with this; this is what it looks like:</p>

<p><img alt="ci-overview.png" src="http://blog.medallia.com/ci-overview.png" width="646" height="231" /></p>

<p>At the top, the two latest release branches are listed, followed by the unmerged branches for each release branch. It also shows the case number in our bug tracker, who made the last commit on the branch, how long ago and how many tests failed. Clicking on the changeset link shows which tests actually failed:</p>

<p><img alt="ci-tests.png" src="http://blog.medallia.com/ci-tests.png" width="616" height="198" /></p>

<p>This screen shows the last few commits on the branch, which tests failed and the execution time of each test. Notice that each test is actually run four times for each changeset; they are run in different order to allow us to detect code which depends on static variables being initialized by other tests.</p>

<p>Finally there is a tree view which makes it easier to visualize branches and how they are merged:</p>

<p><img alt="ci-tree.png" src="http://blog.medallia.com/ci-tree.png" width="447" height="335" /></p>

<p>Clicking on a node in the graph moves the viewpoint to that node, thus making it easy to navigate around in the tree. By default one level of children and 5 levels of parent are shown, and these can be adjusted as necessary.</p>

<p>Together these tools make it reasonably easy to keep track of our repository and manage all the branches. So how is all of this implemented? The web interface is pretty simple: the output from 'hg log' is parsed and used to build a representation of the tree. We use <a href="http://www.graphviz.org/">dot</a> to draw the graphical tree view.</p>

<p>Actually running the tests is a bit more interesting. We have a stand-alone program which executes 'hg pull' every few seconds to grab any new revisions pushed to the repository; once it finds a new revision it hands it off to a separate thread which then compiles the code and starts a separate Java process which actually runs the test cases. This process writes the test results to an XML file every few seconds so we don't have to wait until all the tests have completed before seeing any results (quick feedback is very important).</p>

<p>Since the tests require a lot of resources to run, we actually use several servers to run them; ssh is used to execute commands and start the tests on remote servers, and they write the test results to a shared NFS mount. This way we can test as many changesets concurrently as we want (just limited by how many servers we want to dedicate).</p>

<p>The system is completely automated and thus requires little maintenance. A big advantage of a home-grown system such as this is that it is simple and integrates everything we need in just a few screens. It also makes it easy to add other useful features, such as integration with our bug tracker, so that it shows which features have actually been merged to the release branch.</p>]]>
    </content>
</entry>
<entry>
    <title>Choosing a key-value storage system (Cassandra vs. Voldemort)</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2010/05/choosing_a_keyvalue_storage_sy.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=41" title="Choosing a key-value storage system (Cassandra vs. Voldemort)" />
    <id>tag:blog.medallia.com,2010://1.41</id>
    
    <published>2010-05-07T23:14:39Z</published>
    <updated>2010-05-24T08:31:39Z</updated>
    
    <summary>Motivation At Medallia, a key component of our system currently works with an open source relational db. Since this component mainly queries the db entries by key, we want to try to switch to a key-value storage system and take...</summary>
    <author>
        <name>Diego Erdody</name>
        <uri>na</uri>
    </author>
            <category term="Code" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<h2>Motivation</h2>

<p>At Medallia, a key component of our system currently works with an open source relational db. Since this component mainly queries the db entries by key, we want to try to switch to a key-value storage system and take advantage of several benefits provided by such a system, including distributed replication, load balancing, and failover. One of our objectives is to re-architect this component in a way that will allow us to achieve horizontal scalability, that among other things will help us alleviate the high disk storage requirements we currently have.</p>

<p>Recently we took the time to look into this (and other technological improvements too, exciting times at Medallia right now!), and we reviewed several options. To make a long story short, we ended up with two finalists, <a href="http://cassandra.apache.org/" >Apache Cassandra</a> and <a href="http://project-voldemort.com/">Project Voldemort</a>.  <links></p>

<p>These two projects seem to be the most mature open source options in their class, and both provide a native decentralized clustering support including partitioning, fault tolerance, and high availability. Both are based on <a href="http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html">Amazon's Dynamo paper</a>, but the main difference is that Voldemort follows a simple key/value model, while Cassandra uses a persistency model based on <a href="http://labs.google.com/papers/bigtable.html">BigTable</a>‘s column oriented model. Both provide support for read-consistency where read operations always return latest data, which was a requirement for us. </p>]]>
        <![CDATA[<h2>High level comparison</h2>

<h3>Project Voldemort</h3>

<p>While not an exhaustive list, these are the most relevant pros and cons we identified when reviewing both stores:</p>

<ul>
<li> Pros
	<ul>
	<li> Simpler API
	<li> Persistency based on Berkley DB, a mature and well-known key/value db
	<li> Uses Vector Clocks instead of simple timestamps. It doesn't need the nodes (or clients) clocks to be synchronized
	</ul>
<li> Cons
	<ul>
	<li> No built-in support for "multiple data center"-aware routing (meaning there must be 1 copy of each key in at least one data center)
	</ul>
</ul>

<h3>Apache Cassandra</h3>

<ul>
<li> Pros
	<ul>
	<li> Broader range of systems in production (Facebook, Twitter, Digg, Rackspace)
	<li> Richer API which supports values with a dynamic column structure. The columns can evolve independently, meaning that you can update one column without reading the whole structure.
	<li> Optimized for writes (by design)
	<li> Configurable consistency level (specified on each request)
	</ul>
<li> Cons
	<ul>
	<li> File format is still in development, changes to the internal structure are likely to happen. Due to the flexibility it provides, the file format is more complex and harder to reason with, especially in terms of performance
	<li> Requires Clock Synch (NTP) (for nodes and clients)
	<li> Reads are more disk-intensive than competitors
	<li> Doesn't support client conflict resolution, so the latest update always wins
	</ul>
</ul>

<h2>Performance Tests</h2>

<p>To our surprise <a href="http://www.slideshare.net/adorepump/vpork-nosql" >this</a> was the only link we’ve found that compares the performance for both projects – thus we decided to write this post to share our research. We used the <a href="http://wiki.github.com/trav/vpork/vpork">vpork</a> test framework, which we modified to suit our needs by upgrading the client code to the latest versions, adding a warm-up phase, and adding rewrite capabilities. These are the results of our tests:</p>

<p>Setup:</p>

<ul>
<li>Versions 
   <ul>
    <li> Voldemort v0.80.1
    <li> Cassandra 0.6.0-beta3 
   </ul>
<li> Boxes: 3 similar nodes with the following spec:
   <ul>
       <li> 4GB maximum heap size
	<li> Replication parameters: N=3 (replicas for each entry), R=2 (nodes to wait for on each read), W=2 (nodes to block for on each write)
	<li> 8 processors on each server (Intel(R) Xeon(R) CPU E5504 @ 2.00GHz)
        <li> 1TB disk space (Seagate ST31000340NS, 7200 RPM, 32MB cache)
   </ul>
<li> Persistence parameters
   <ul>
   <li>Voldemort (<a href="http://project-voldemort.com/configuration.php">default values</a>)
     <ul>
        <li>key-serializer: string
        <li>value-serializer: identity (byte array)
        <li>persistence engine=bdb (Berkley DB)
        <li>bdb.cache.size=1536MB
     </ul>
   <li>Cassandra
     <ul>
        <li>ColumnFamily definition: CompareWith="BytesType" RowsCached="10000"
        <li>ReplicationFactor=3
        <li>Partitioner=org.apache.cassandra.dht.RandomPartitioner
        <li>ConcurrentReads=16
        <li>ConcurrenWrites=32
     </ul>
   </ul>
<li> Tests
   <ul>
    <li> Client Threads: 40
	<li> Initial load: 5 million records - records present before starting each test
	<li> WarmUp: 20K records - initial writes before measuring time for each test
	<li> Number of operations per test: 500K 
   </ul>
</ul>

<p>We ran tests for 4 different write-rewrite-read configurations. A write is equivalent to a put operation with a new record (non-existing key). A rewrite is a put operation with an existing key. A read is a get operation on an existing key. These are the configurations we tested:</p>

<ul>
<li> 50% Write 50% Read
<li> 10% Write 40% Rewrite 50% Read
<li> 50% Rewrite 50% Read
<li> 90% Rewrite 10% Read 
</ul>

<p>We ran all the tests for two different value sizes, 15 and 1.5 KB. Even though we evaluated different options, for our current needs, the last one with a 15 KB data entry was the most representative scenario.</p>

<p>The first pair of charts shows the latency, or average time it takes a read or write operation to complete in each case. Lower values are better. As expected, Cassandra write (and rewrite) times were consistently faster than Voldemort, while read times varied a bit depending on the scenario but were more or less the same in general.</p>

<table>
<tr><td>
<img alt="test-avg-lat-1.5.png" src="http://blog.medallia.com/test-avg-lat-1.5.png" width="500" height="300" />
</td><td>
<img alt="test-avg-lat-15.png" src="http://blog.medallia.com/test-avg-lat-15.png" width="500" height="300" />
</td></tr>
</table>

<p>The second pair of charts shows the maximum time in the best 99% of cases; again lower values are better:</p>

<table>
<tr><td>
<img alt="test-99-lat-1.5.png" src="http://blog.medallia.com/test-99-lat-1.5.png" width="500" height="300" />
</td><td>
<img alt="test-99-lat-15.png" src="http://blog.medallia.com/test-99-lat-15.png" width="500" height="300" />
</td></tr>
</table>

<p>On the front-end, we have a write-back cache which means that write operations don't affect the user experience. On the other hand, read operations are directly related to page loads. That's why we were concerned about the peak for Cassandra read in the last scenario for 15KB. We ran some further tests to measure the 99.9% and 99.99% percentiles and the difference was even greater: 5050 ms for Cassandra and 748 ms for Voldemort in the first case, and 9176 ms against 1129 ms in the second case. This huge difference was a key decision factor for us.</p>

<p>Finally, these two charts show the general throughput in terms of operations (read or write) per second. In this case higher values are better:</p>

<table>
<tr><td>
<img alt="test-ops-1.5.png" src="http://blog.medallia.com/test-ops-1.5.png" width="450" height="300" />
</td><td>
<img alt="test-ops-15.png" src="http://blog.medallia.com/test-ops-15.png" width="450" height="300" />
</td></tr>
</table>

<p>Notes:</p>

<ul>
    <li> Cassandra commit log and data folder are supposed to be placed at different disks to improve performance, we tested with both on the same disk. 
</ul>

<p>Issues found while testing:</p>

<ul>
    <li> Voldemort client.put(K key, V value) (not the one that takes a Version object) throws ObsoleteVersionException if called with the same key from different threads. The javadoc states "Associated (sic) the given value to the key, clobbering any existing values stored for the key. ", so this was not expected.
</ul>

<h2>And the winner is ...</h2>

<p>I think there is no clear winner, in general terms. The best option depends on many factors that each company has to evaluate. My preference changed a few times during the review and tests.</p>

<p>Having said that, we had to choose one, and we decided to go with Project Voldemort. The main reasons were the simplicity, better versioning control, persistency layer maturity, and latency predictability. </p>

<p>We are currently developing the new solution, and it will take some time before we can put it in production, but we wanted to share our preliminary results with everyone who is considering one of these two options, so they’ll have one more tool at the time of the decision.</p>

<p>We'll keep you posted on how it goes.</p>

<p>Diego Erdody<br />
Lead Software Engineer</p>

<p><br />
Other useful articles comparing different key-value stores:</p>

<ul>
	<li> <a href="http://blog.endpoint.com/2010/03/nosql-live-dynamo-derivatives-cassandra.html" > http://blog.endpoint.com/2010/03/nosql-live-dynamo-derivatives-cassandra.html </a>
	<li> <a href="http://www.vineetgupta.com/2010/01/nosql-databases-part-1-landscape.html" > http://www.vineetgupta.com/2010/01/nosql-databases-part-1-landscape.html </a>
	<li> <a href="http://arstechnica.com/business/data-centers/2010/02/-since-the-rise-of.ars/2" > http://arstechnica.com/business/data-centers/2010/02/-since-the-rise-of.ars/2 </a>
	<li> <a href="http://www.rackspacecloud.com/blog/2009/11/09/nosql-ecosystem/" > http://www.rackspacecloud.com/blog/2009/11/09/nosql-ecosystem/ </a>
	<li> <a href="http://bhavin.directi.com/tag/memcached/" > http://bhavin.directi.com/tag/memcached/ </a>
	<li> <a href="http://www.metabrew.com/article/anti-rdbms-a-list-of-distributed-key-value-stores/" > http://www.metabrew.com/article/anti-rdbms-a-list-of-distributed-key-value-stores/ </a> 
</ul>
]]>
    </content>
</entry>
<entry>
    <title>Medallia is recruiting top talent!</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2010/04/medallia_is_recruiting_top_tal.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=40" title="Medallia is recruiting top talent!" />
    <id>tag:blog.medallia.com,2010://1.40</id>
    
    <published>2010-04-22T23:42:46Z</published>
    <updated>2010-05-10T17:35:33Z</updated>
    
    <summary>If you got to our blog, you probably already know about us, but just in case you need more information, here you go: Medallia is a fast-growing, profitable, privately held technology company located in the heart of Silicon Valley, in...</summary>
    <author>
        <name>Medallia</name>
        <uri>na</uri>
    </author>
            <category term="Jobs" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p>If you got to our blog, you probably already know about us, but just in case you need more information, here you go:</p>

<p>Medallia is a fast-growing, profitable, privately held technology company located in the heart of Silicon Valley, in Menlo Park, CA. We build great Software-as-a-Service (SaaS) based solutions for Global 2000 companies, and we have a 100% client recommendation rate. More than 50,000 businesses and business units use our products to gather, analyze, and act on feedback from customers, partners, and employees, including Fidelity, Four Seasons, Sephora, Hyatt, Gap, and Lego. Our customers delivered more than 400 million survey pages using Medallia in 2009 alone. By adopting Medallia’s products, companies can better understand and adapt to customer needs. More satisfied and loyal customers, in turn, help generate better business results. In fact, measured in terms of market capitalization, publicly-traded Medallia customers have outperformed the S&P 500 10X since 2003 and 4X since 2008. </p>

<p>Medallia is also a great place to work, with an unconventional, creative, collaborative, intellectual, and positive environment. We have an unusually low turnover rate, with less than 10% of employees voluntarily leaving the company, and most of those for reasons unrelated to Medallia — like to join a spouse relocating to Europe. Of the few employees who have left, 30% have actually returned! We are also finalists for the SF Times best workplace award, which will be awarded in the coming weeks. We hire inspiring people you will like working with. To find out more about our company culture, please visit <a href="http://medallia.com/careers/opportunity">http://medallia.com/careers/opportunity</a></p>

<p>We actively seek talented people for the following positions:</p>

<p>1) Software Engineers<br />
  We are hiring java experts at all levels - entry-level, senior, and lead positions. If you are a passionate programmer who lives and breathes to develop innovative algorithms, please check out our full job descriptions below: <br />
  <a href="http://www.medallia.com/careers/position/software-engineer/">http://www.medallia.com/careers/position/software-engineer/</a><br />
  <a href="http://www.medallia.com/careers/position/senior-software-engineer/">http://www.medallia.com/careers/position/senior-software-engineer/</a></p>

<p>2) Summer Software Engineering Interns<br />
 We invite student java experts to spend the summer working on innovative projects with us, including data mining, visualization, and more. We welcome students who are looking for an opportunity to apply their research work to practical problem solving that we can incorporate into our application. Preference is given to students within one year of graduation, but exceptional java developers will be considered at any point in their education. Apply soon, as these positions are filling up quickly!<br />
  <a href="http://www.medallia.com/careers/position/2010-summer-engineering-internships/">http://www.medallia.com/careers/position/2010-summer-engineering-internships/<br />
</a><br />
3) Operations Engineers<br />
 We are looking for both Operations Engineers and IT/Systems Administrators who will enjoy working with our talented software engineers and client services team to keep our application running smoothly.<br />
  <a href="http://www.medallia.com/careers/position/operations-engineer1/">http://www.medallia.com/careers/position/operations-engineer1/</a><br />
  <a href="http://www.medallia.com/careers/position/it-systems-administrator/">http://www.medallia.com/careers/position/it-systems-administrator/</a></p>

<p>4) Web/Graphic Designers<br />
  We seek someone with an impressive online portfolio to play a key role in designing our web and print presence through new web site initiatives, as well as the development of marketing materials (both<br />
print and online). <br />
  <a href="http://www.medallia.com/careers/position/web-graphic-designer/">http://www.medallia.com/careers/position/web-graphic-designer/</a></p>

<p>5) Office Assistant/Admin (30 - 40 hours per week)<br />
  We seek a smart, friendly office assistant who multi-tasks well and is able to work with minimal guidance. The ideal candidate will have a car available for running errands, and will be available to work 30 or more hours per week, including weekday afternoons until 6:30 pm.<br />
  <a href="http://www.medallia.com/careers/position/office-assistant/">http://www.medallia.com/careers/position/office-assistant/<br />
</a><br />
6) Client Service Managers and Senior Managers<br />
We are seeking Client Service Managers and Senior Managers who can take ownership of specific Fortune 500 accounts from the first day. Medallia’s Client Services Managers build deep relationships with top management at client companies, leverage those relationships to understand underlying client needs, then channel Medallia’s engineering and management resources to address those needs – often through innovative software solutions.<br />
  <a href="http://www.medallia.com/careers/position/client-services-manager-senior-manager/">http://www.medallia.com/careers/position/client-services-manager-senior-manager/</a></p>

<p>7) Analyst and senior analysts<br />
  We seek quick-learning, articulate, and analytical members of our client services team, where responsibilities include a blend of account management, project management, data analysis, product<br />
development, and business consulting.<br />
  <a href="http://www.medallia.com/careers/position/analyst-and-senior-analyst/">http://www.medallia.com/careers/position/analyst-and-senior-analyst/</a></p>

<p>8) Product Marketing Manager<br />
  Medallia is looking for an enthusiastic and talented product marketer to partner with our product and marketing teams and develop compelling collateral and provide key strategic contributions. The ideal candidate for this position will have demonstrated cross-functional leadership.<br />
  <a href="http://www.medallia.com/careers/position/product-marketing-manager/">http://www.medallia.com/careers/position/product-marketing-manager/</a></p>

<p>9) Staff Accountant<br />
  We are seeking a Staff Accountant with working knowledge of the general ledger function and US GAAP  for internal corporate accounting. This position will support much of the general ledger<br />
activity in our US parent company as well as for two foreign subsidiaries.<br />
  <a href="http://www.medallia.com/careers/position/staff-accountant/">http://www.medallia.com/careers/position/staff-accountant/</a></p>

<p>To apply, please review our hiring process at <a href="http://www.medallia.com/careers/hiring-process">http://www.medallia.com/careers/hiring-process</a>, and then send your resume and cover letter to jobs@medallia.com, with the job title in the subject of your email.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Medallia Expands Its Recruiting Efforts to Argentina</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2008/12/medallia_expands_its_recruitin_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=39" title="Medallia Expands Its Recruiting Efforts to Argentina" />
    <id>tag:blog.medallia.com,2008://1.39</id>
    
    <published>2008-12-12T21:36:46Z</published>
    <updated>2008-12-16T23:57:10Z</updated>
    
    <summary>On October 16th and 17th, 2008, Juan Pablo Dellarroquelle, Medallia’s VP  of Engineering, flew to Argentina to attend a career fair at ITBA - Instituto Tecnológico de Buenos Aires (Buenos Aires Institute of Technology).  Formally a student at the university, he was now there to recruit students for full-time and internship opportunities in Medallia’s Engineering Department.</summary>
    <author>
        <name>Erin Storm</name>
        <uri>http://blog.medallia.com</uri>
    </author>
            <category term="Announcements" />
            <category term="Jobs" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p><img  style="float:right;margin:0 0 10px 10px;" src="/jpargentina.jpg" alt="Juan Pablo Dellarroquelle, VP of Engineering, and Diego Erody, Engineer, conversing with recruiting candidate">On October 16th and 17th, 2008, Juan Pablo Dellarroquelle, Medallia’s VP  of Engineering, flew to Argentina to attend a career fair at ITBA - Instituto Tecnológico de Buenos Aires (Buenos Aires Institute of Technology).  Formally a student at the university, he was now there to recruit students for full-time and internship opportunities in Medallia’s Engineering Department.</p>

<p>Being the new kids on the block, Medallia representatives spoke to about 30 students in all over the two days that the fair was held.  “The first day was a bit slow,” said Juan Pablo. “Only a few students knew about us attending the fair." As word spread, more and more students became interested in the opportunity of being part of an elite team of developers that is building an actual product - right in the heart of Silicon Valley.</p>

<p>The door has been opened…</p>

<p>Recruiting students at local universities as well as those abroad is something that Medallia strives to do.  With the help of Juan Pablo and a few fellow Argentines, Medallia looks forward to returning to ITBA next year to recruit more world class students, and is also hoping to build a lasting relationship with the institution. Juan Pablo concluded, ”I believe this is a great opportunity for us to attract great talent, and for students to gain unique work and cultural experience in the U.S.”</p>]]>
        
    </content>
</entry>
<entry>
    <title>iPod + iPhone + Web Mashup</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2008/11/ipod_iphone_web_mashup_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=37" title="iPod + iPhone + Web Mashup" />
    <id>tag:blog.medallia.com,2008://1.37</id>
    
    <published>2008-11-26T07:38:43Z</published>
    <updated>2008-11-26T15:39:56Z</updated>
    
    <summary>It&apos;s what the mobile music experience could be This project started as I explored ways to view lyrics while listening to my music library on the iPod Touch. Ideas kept coming and I added some concepts (and code) from iMovieMash.com...</summary>
    <author>
        <name></name>
        
    </author>
            <category term="iPhone" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[<p><strong>It's what the mobile music experience could be</strong></p>

<p>This project started as I explored ways to view lyrics while listening to my music library on the iPod Touch.  Ideas kept coming and I added some concepts (and code) from iMovieMash.com plus great content from the multitude of public video, music and search APIs.</p>

<p>The result was <a href="http://imusicmash.com" target="_blank">iMusicMash.com</a>, an iPhone and Android G1 social web application that takes your music experience to a whole new level of enjoyment and discovery. You can start with the friends' playlists we already have or load your own iTunes music library.  The interface is familiar as it mimics the iPhone's iPod.  For each artist, we bring photos from Yahoo Boss Image Search, concert dates from Eventful, and live Twitter discussions.  Then, for each song, we bring great YouTube videos, lyrics from LyricWiki, similar songs from Last.fm, and friends' songs for the same artist.</p>

<p>I recently added lyrics search and artist/title search.</p>

<p>iMusicMash was a winner in the Yahoo Developer Mashup contest at the recent <a href="http://www.mashupcamp.com/" target="_blank"> Mashup Camp</a> in Mt. View, California.</p>]]>
        <![CDATA[<p>On the technical front, <a href="http://imusicmash.com" target="_blank">iMusicMash.com</a> was developed with Perl for the backend and the IUI iPhone framework for the front end. It looks best on the iPhone or iPod Touch or Android G1.  </p>

<p>We don't access the mobile device's music library directly, rather,  we have a utility with which you can upload your iTunes XML file to iMusicMash from your desktop or laptop.  We provide you a personal URL so that you can bookmark your library to appear on the mobile site's home page.  (iPhone icon is available if you click "+").  </p>

<p>These are some of the API's I used:</p>

<p>YouTube<br />
(for music videos)<br />
http://code.google.com/apis/youtube/2.0/reference.html</p>

<p>Yahoo BOSS Search & Image Search API<br />
(for artist images and lyrics search)<br />
http://developer.yahoo.com/search/boss/boss_guide/</p>

<p>Last.fm<br />
(for similar songs)<br />
http://www.last.fm/api</p>

<p>Seeqpod API<br />
(for MP3s)<br />
http://www.seeqpod.com/api.php</p>

<p>Eventful API<br />
(for concert events)<br />
http://api.eventful.com/</p>

<p>Twitter API<br />
(for discussions on each artist)<br />
http://apiwiki.twitter.com/</p>

<p><br />
Al Nevarez<br />
Product Manager </p>]]>
    </content>
</entry>
<entry>
    <title>Spider Web Framework (for Java)</title>
    <link rel="alternate" type="text/html" href="http://blog.medallia.com/2008/11/spider_web_framework_for_java.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=36" title="Spider Web Framework (for Java)" />
    <id>tag:blog.medallia.com,2008://1.36</id>
    
    <published>2008-11-04T04:44:57Z</published>
    <updated>2008-11-04T05:26:50Z</updated>
    
    <summary>The Spider Web Framework is a framework for building web applications in Java. It was developed with a set of specific goals: Make it trivially easy to write good test cases Reduce boilerplate code to a minimum Avoid static state...</summary>
    <author>
        <name>Kristian Eide</name>
        
    </author>
            <category term="Code" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.medallia.com/">
        <![CDATA[The <a href="http://spiderweb.googlecode.com/">Spider Web Framework</a> is a framework for building web applications in Java. It was developed with a set of specific goals:

<ul>
  <li>Make it trivially easy to write good test cases</li>
  <li>Reduce boilerplate code to a minimum</li>
  <li>Avoid static state through dependency injection</li>
  <li>Strict M-V-C separation</li>
  <li>Prefer convention over configuration</li>
</ul>

Before diving into the details of how each of these goals were achieved I would like to mention that the source code for the framework is <a href="http://github.com/kreide/spiderweb/">available</a> as well as a sample application with a <a href="http://code.google.com/p/spiderweb/wiki/CalculatorSampleApplication">tutorial</a>. The sample application includes Jetty and can thus be started with a single command (Java and Ant required).]]>
        <![CDATA[<h3><a name="UnitTesting"></a>Unit testing</h3>

<p>
One of the most important feature of a framework is to facilitate testing; Spiderweb includes
a testing framework that makes it trivial to write comprehensive test cases; a complete test,
excluding the class and method declarations, can be written as:
</p>

<pre>
assertHasContent(action(), "foo", "bar");
</pre>

<p>
This will actually test the whole stack; HttpServletRequest and HttpServletResponse objects are
instantiated and passed in to a servlet instance, and the data written to the response object is what is actually checked. The above checks that rendering a page without any request parameters returns a
page that includes the strings "foo" and "bar".
</p>

<h3><a name="RequestParameterParsing"></a>Request parameter parsing</h3>

<p>
The HTTP protocol is text based, which means that any web application needs to parse request parameters
into proper data types; this includes integers, enums and any custom data types defined by each
application. This code tends to either be duplicated or at the very least need a method call for each
request parameter to convert it into the right data type. Spiderweb handles this via a proxy interface
which is dependency injected. Custom parsers can also be added easily.
</p>

<h3><a name="DependencyInjection"></a>Dependency injection</h3>

<p>
A web application often has several services and / or background tasks that are configured and instantiated
when the servlet starts, typically in the Servlet.init() method. Since each module of
the application typically needs to use a different set of these services a way to get references to
the objects is needed. Often this is done by putting the references into static variables or having an
object that has references to all the services and pass this object to all modules of the app. Both
approaches make it difficult to determine which services a given module needs.
</p>

<p>
Spiderweb solves this problem by dependency injecting the needed services; the dependencies are thus
documented simply as a list of arguments.
</p>

<h3><a name="MVCSeparation"></a>M-V-C separation</h3>

<p>
M-V-C is the preferred approach for an application that presents a UI, however, it turns out that, for
a number of reasons, it is hard to keep this separation in practice. Spiderweb attempts to solve this
problem by using StringTemplate as its templating language. StringTemplate was developed specifically
to make a templating language with enough expressive power to make it useful, but no more. The author
of StringTemplate wrote a <a href="http://www.cs.usfca.edu/~parrt/papers/mvc.templates.pdf">paper</a>
going into detail on the motivation for StringTemplate.
</p>

<p>
Spiderweb goes a step further requiring all attributes used in the template be listed using TypeTags;
these tags serve both as documentation for the template as well as a type safe way to set attributes.
</p>

<h3><a name="ConventionOverConfiguration"></a>Convention over configuration</h3>

<p>
Paradoxically having no choice can often be liberating; if there is only one way to do something
the focus can simply be on actually getting it done.
</p>

<p>
Configuration for a web application tends to be very repetitive since most teams, if they are well
organized, will adopt conventions to avoid having to check configuration files all the time. The
configuration is thus copied and pasted each time a new module is added. In addition to being extra
work this duplication also increases the maintenance burden.
</p>

<p>
Spiderweb solves this by having no mandatory configuration (beyond the minimum required for a Java Servlet).
A URI maps to a name of a class and the URI is valid if that class exists. Various parameters
can be changed, however, but this is typically done by method overriding instead of external configuration
files (which cannot be automatically refactored and are not checked at compile time).
</p>

<p>
<b>A tutorial that goes through writing a simple application can be found <a href="http://code.google.com/p/spiderweb/wiki/CalculatorSampleApplication">here</a>.</b>
</p>]]>
    </content>
</entry>
<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></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>2008-08-11T12:29:38Z</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>2008-08-11T12:29:33Z</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>2008-08-11T12:29:27Z</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>2008-08-11T12:29:23Z</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>Medallia</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>

</feed> 


