<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8639197052884293768</id><updated>2012-01-31T01:21:40.633-06:00</updated><title type='text'>Chris Miceli</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>28</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-7320340507830937515</id><published>2011-11-20T16:43:00.001-06:00</published><updated>2011-11-27T20:11:47.115-06:00</updated><title type='text'>Implementing Generators/Yield in Languages Without Support</title><content type='html'>As a follow up to my previous post, I intent to go into detail how generators are actually implemented in a language. The way I intend to do this is to actually implement the generator paradigm without using language provided tools such as keywords. The first step to this process is actually understanding what is happening when you use the yield keyword. Perhaps an simple walk through will be illustrative.&lt;br /&gt;&lt;br /&gt;A function that wishes to use a generator will iterate over that generator. To the function using the generator, the generator acts more like a data structure that implements the enumerable (iterable) interface than a function at all. The generator function cannot be called except by iterating over it. This is the proper way to think of a generator, a data structure. If you are only using a generator, than this is all you need to know. Implementing a generator requires a little more detail. Let's examine a the most basic generator, one that counts down. This example uses, C#, but the syntax is only slightly different than other languages such as python.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public IEnumerable&amp;lt;int&amp;gt; count(int start, int end)&lt;br /&gt;{&lt;br /&gt;   int counter = end;&lt;br /&gt;   while (counter &amp;lt;= end)&lt;br /&gt;   {&lt;br /&gt;      yield return counter;&lt;br /&gt;      counter++;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I used a while loop here intentionally so the control flow is obvious. Up until the yield statement, everything is normal. So what is happening at "yield return counter"? The function execution stops and returns the variable counter for each "call" happening indirectly through the iterator. So what happens the next time the iterator issues a call to this function? Well, the execution picks up at counter++! But what is the value of counter? The special yield return statement is saving the entire state of the generator(local variables, instruction pointer, and any &lt;i&gt;other state information&lt;/i&gt;), allowing the generator to be resumed exactly where it left off. I'll get to that other information later. To wrap up the basic, right before yielding a value, save the state of the generator. Upon entering the generator again, restore the saved state and jump to where we left off.&lt;br /&gt;&lt;br /&gt;Let's examine another example. This time we will be looking at a recursive implementation of our count generator. I'm going to be intentionally avoiding the use of foreach to bring out the enumerator (iterator).&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public IEnumerable&amp;lt;int&amp;gt; count(int start, int end)&lt;br /&gt;{&lt;br /&gt;   yield return start;&lt;br /&gt;   if (start != end)&lt;br /&gt;   {&lt;br /&gt;      // foreach (int result in count(start + 1, end))&lt;br /&gt;      // {&lt;br /&gt;      //    yield return result;&lt;br /&gt;      // }&lt;br /&gt;      IEnumerator&amp;lt;int&amp;gt; enumerator = count(start + 1, end).GetEnumerator();&lt;br /&gt;      while (false != enumerator.MoveNext())&lt;br /&gt;      {&lt;br /&gt;         yield return enumerator.Current;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This generator does the same thing, just in a recursive fashion. The first yield is exactly as the one previously examined. Things get slightly more difficult to keep track when the recursion begins, but the same exact process is followed. The enumerator is saved as part of the state of the count generator. When returning, the iterator is restored and so the generator continues as expected.&lt;br /&gt;&lt;br /&gt;If C# allowed us to directly recur on the generator itself instead of iterating over the results as shown below:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public IEnumerable&amp;lt;int&amp;gt; count(int start, int end)&lt;br /&gt;{&lt;br /&gt;   yield return start;&lt;br /&gt;   if (start != end)&lt;br /&gt;   {&lt;br /&gt;      // Will not compile&lt;br /&gt;      yield return count(start + 1, end);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;then the state would have to include the call stack of the recursion produced by the generator. By explicitly restricting yield to return the enumerated base type (int), we are prevented from this operation because count returns an enumerable type. This makes implementing generators manually easier. We don't have to worry about recursion at all.&lt;br /&gt;&lt;br /&gt;So now we get to implementing a generator. The basic ideas have been captured above. We need to save locals upon yielding, restore state upon calling, and allow enumeration. Since we generators are essentially data structures, we are going to have our desired operation (count) be a member function of a class that extends from a Generator class. Then your program can call foreach on this data type. Let's shown the Generator class first.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;class Generator&amp;lt;T, State, RetType&amp;gt;&lt;br /&gt;&lt;br /&gt;   : IEnumerable&amp;lt;RetType&amp;gt; where T : GeneratorIterator&amp;lt;State, RetType&amp;gt;, new()&lt;br /&gt;{&lt;br /&gt;   public Generator(State initialState)&lt;br /&gt;   {&lt;br /&gt;      this.initialState = initialState;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private State initialState;&lt;br /&gt;&lt;br /&gt;   #region IEnumerable&lt;br /&gt;   public IEnumerator&amp;lt;RetType&amp;gt; GetEnumerator()&lt;br /&gt;   {&lt;br /&gt;      GeneratorIterator&amp;lt;State, RetType&amp;gt; yieldedFunction = new T();&lt;br /&gt;      yieldedFunction.Initialize(initialState);&lt;br /&gt;      return yieldedFunction;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   IEnumerator IEnumerable.GetEnumerator()&lt;br /&gt;   {&lt;br /&gt;      return this.GetEnumerator();&lt;br /&gt;   }&lt;br /&gt;   #endregion&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public abstract class GeneratorIterator&amp;lt;State, RetType&amp;gt; : IEnumerator&amp;lt;RetType&amp;gt;&lt;br /&gt;{&lt;br /&gt;   public void Initialize(State initialState)&lt;br /&gt;   {&lt;br /&gt;      this.initialState = initialState;&lt;br /&gt;      this.currentState = initialState;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public RetType YieldReturn(State state, RetType result)&lt;br /&gt;   {&lt;br /&gt;      // Save state before returning&lt;br /&gt;      this.currentState = state;&lt;br /&gt;      return result;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private State initialState;&lt;br /&gt;&lt;br /&gt;   private State currentState;&lt;br /&gt;&lt;br /&gt;   private RetType nextResult;&lt;br /&gt;&lt;br /&gt;   public abstract RetType function(State currentState);&lt;br /&gt;&lt;br /&gt;   #region IEnumerator&lt;br /&gt;   public RetType Current&lt;br /&gt;   {&lt;br /&gt;      get&lt;br /&gt;      {&lt;br /&gt;         return this.nextResult;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   object IEnumerator.Current&lt;br /&gt;   {&lt;br /&gt;      get&lt;br /&gt;      {&lt;br /&gt;         return this.Current;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void Reset()&lt;br /&gt;   {&lt;br /&gt;      // Set the state back and invalid nextResult&lt;br /&gt;      this.Initialize(this.initialState);&lt;br /&gt;      this.nextResult = default(RetType);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public bool MoveNext()&lt;br /&gt;   {&lt;br /&gt;      this.nextResult = this.function(this.currentState);&lt;br /&gt;      return this.currentState != null;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void Dispose() { }&lt;br /&gt;   #endregion&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Let's examine what this class is doing. It is taking a class that is expected to override a member called function. This will be the function that is expected to be using the YieldReturn method provided by this class. Most of the code is setting up the enumerator. The enumerator takes care of calling the function when appropriate. The real magic that enables this class to be a generator is the currentState variable. This is where the function's state is saved. Whenever the function is needed, the function is passed the current state that was saved by YieldReturn. The function is responsible for using the state to produce the expected results.&lt;br /&gt;&lt;br /&gt;To actually use the state, we are going to have functions that resemble &lt;a href="http://en.wikipedia.org/wiki/Finite-state_machine"&gt;finite state machines&lt;/a&gt; more than traditional functions. This is due to limitations of the C# compiler to allow us to jump to exactly where we need to. Below is a version of the first non recursive count and the appropriate state class representing all locals.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;class Count : GeneratorIterator&amp;lt;CountState, int&amp;gt;&lt;br /&gt;{&lt;br /&gt;   public override int function(CountState currentState)&lt;br /&gt;   {&lt;br /&gt;      if (currentState.stateIndex == 0)&lt;br /&gt;      {&lt;br /&gt;         currentState.counter = currentState.start;&lt;br /&gt;         currentState.stateIndex = 1;&lt;br /&gt;         // Proceed to state 1&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (currentState.stateIndex == 1)&lt;br /&gt;      {&lt;br /&gt;         while (currentState.counter &amp;lt;= currentState.end)&lt;br /&gt;         {&lt;br /&gt;            // Set the next state&lt;br /&gt;            currentState.stateIndex = 2;&lt;br /&gt;            // yield return&lt;br /&gt;            return YieldReturn(currentState, currentState.counter);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         // Signal no more to yield, normally accomplished by reaching end of the function&lt;br /&gt;         return YieldReturn(null, default(int));&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (currentState.stateIndex == 2)&lt;br /&gt;      {&lt;br /&gt;         currentState.counter = currentState.counter + 1;&lt;br /&gt;         currentState.stateIndex = 1;&lt;br /&gt;         // Use recursion to jump to state already passed&lt;br /&gt;         return function(currentState);&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      // Can only get here if an invalid stateIndex was given&lt;br /&gt;      throw new Exception("Unreachable");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class CountState&lt;br /&gt;{&lt;br /&gt;   public int stateIndex;&lt;br /&gt;   public int start;&lt;br /&gt;   public int end;&lt;br /&gt;   public int counter;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The stateIndex variable of the CountState class is used to determine where in the code path we left off. The function has no locals to avoid having variables no properly restored when upon reentry. To use this generator, we simply instantiate the wrapper and then the class behaves as all enumerator types do.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;CountState initialState = new CountState&lt;br /&gt;{&lt;br /&gt;   start = 0,&lt;br /&gt;   end = 5,&lt;br /&gt;   stateIndex = 0&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Generator&amp;lt;Count, CountState, int&amp;gt; generator = new Generator&amp;lt;Count, CountState, int&amp;gt;(initialState);&lt;br /&gt;foreach (int result in generator)&lt;br /&gt;{&lt;br /&gt;   Console.WriteLine(result);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;To illustrate that recursion is supported, I am translated the recursive count above to an appropriate finite state machine. You can try for yourself, but you can observe that there is no need to save a call stack to support recursion in your generators.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;class RecursiveCount : GeneratorIterator&amp;lt;RecursiveCountState, int&amp;gt;&lt;br /&gt;{&lt;br /&gt;   public override int function(RecursiveCountState currentState)&lt;br /&gt;   {&lt;br /&gt;      if (currentState.stateIndex == 0)&lt;br /&gt;      {&lt;br /&gt;         currentState.stateIndex = 1;&lt;br /&gt;         return YieldReturn(currentState, currentState.start);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (currentState.stateIndex == 1)&lt;br /&gt;      {&lt;br /&gt;         if (currentState.start == currentState.end)&lt;br /&gt;         {&lt;br /&gt;            // We are done, signal no more results in this generator&lt;br /&gt;            currentState.stateIndex = 3;&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            /// repeat&lt;br /&gt;            currentState.recursiveCall = new Generator&amp;lt;RecursiveCount, RecursiveCountState, int&amp;gt;(&lt;br /&gt;               new RecursiveCountState&lt;br /&gt;                  {&lt;br /&gt;                     start = currentState.start + 1,&lt;br /&gt;                     end = currentState.end,&lt;br /&gt;                     stateIndex = 0&lt;br /&gt;                  }).GetEnumerator();&lt;br /&gt;            // Go to state 2&lt;br /&gt;            currentState.stateIndex = 2;&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (currentState.stateIndex == 2)&lt;br /&gt;      {&lt;br /&gt;         while (false != currentState.recursiveCall.MoveNext())&lt;br /&gt;         {&lt;br /&gt;            return YieldReturn(currentState, currentState.recursiveCall.Current);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         // We are done, signal no more results in this generator&lt;br /&gt;         currentState.stateIndex = 3;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if (currentState.stateIndex == 3)&lt;br /&gt;      {&lt;br /&gt;         return YieldReturn(null, default(int));&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      throw new Exception("Unreachable");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class RecursiveCountState&lt;br /&gt;{&lt;br /&gt;   public int stateIndex;&lt;br /&gt;   public int start;&lt;br /&gt;   public int end;&lt;br /&gt;   public IEnumerator&amp;lt;int&amp;gt; recursiveCall;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I hope that this has been informative of the inner workings of generators and the yield statement. Please comment below with any questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-7320340507830937515?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/7320340507830937515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=7320340507830937515' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/7320340507830937515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/7320340507830937515'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/11/implementing-generatorsyield-in.html' title='Implementing Generators/Yield in Languages Without Support'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-5068202615385277968</id><published>2011-11-04T00:38:00.000-05:00</published><updated>2011-11-04T00:38:34.512-05:00</updated><title type='text'>Yield statement in C#</title><content type='html'>My great friend recently did on his &lt;a href="http://thecodegalaxy.blogspot.com/"&gt;wonderful blog&lt;/a&gt;&amp;nbsp;covered in a &lt;a href="http://thecodegalaxy.blogspot.com/2011/11/combinations-permutations-and-python.html"&gt;recent post&lt;/a&gt; the basics of generators in Python. To further my own knowledge about&amp;nbsp;generators, especially in the language I use&amp;nbsp;most at work, I decided to port his permutation function to C#,&amp;nbsp;yield statement&amp;nbsp;and all.&lt;br /&gt;&lt;br /&gt;To basically reiterate what my friend stated, the yield statement allows a function's state to be saved.&amp;nbsp;For functions that are designed to generate a set of data to be iterated over this is great. Instead of computing the entire list and storing the results in memory,&amp;nbsp;the function is able to pick up where it left off and generate the next element of the set when requested. Here is an example&amp;nbsp;with a function that generates permutations.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;   private static IEnumerable&amp;lt;string&amp;gt; Permutations(string input)&lt;br /&gt;   {&lt;br /&gt;      List&amp;lt;string&amp;gt; result = new List&amp;lt;string&amp;gt;();&lt;br /&gt;      if (string.IsNullOrEmpty(input))&lt;br /&gt;      {&lt;br /&gt;         yield return string.Empty;&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;         for (int i = 0; i &amp;lt; input.Count(); i++)&lt;br /&gt;         {&lt;br /&gt;            foreach (string permutation in Permutations(input.Substring(0, i) + input.Substring(i + 1)))&lt;br /&gt;            {   &lt;br /&gt;               yield return input[i] + permutation;&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;If you iterate over this function, you will notice that the entire list is never generated entirely in memory. The syntax would be something along the lines of:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;   foreach (string permutation in Permutations("vegetable"))&lt;br /&gt;      {&lt;br /&gt;         System.Console.WriteLine(permutation);&lt;br /&gt;      }&lt;br /&gt;&lt;/pre&gt;Thanks to my friend for helping me understand this topic and bring attention to features of a language I use every day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-5068202615385277968?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/5068202615385277968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=5068202615385277968' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/5068202615385277968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/5068202615385277968'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/11/yield-statement-in-c.html' title='Yield statement in C#'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-8776828054102986580</id><published>2011-10-25T22:15:00.000-05:00</published><updated>2011-10-25T22:15:19.744-05:00</updated><title type='text'>Time Lapse</title><content type='html'>Recently, I set up my server with a copy of &lt;a href="http://www.yawcam.com/"&gt;Yawcam&lt;/a&gt; on my home server. The initial plan was to experiment with using a webcam for security purposes, but found myself a little creeped out. I decided to turn the camera away from the door and out to the window. I set the software to take a picture every 10 seconds for a full day. You can see the results on &lt;a href="http://vimeo.com/31066911"&gt;Vimeo&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-8776828054102986580?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/8776828054102986580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=8776828054102986580' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/8776828054102986580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/8776828054102986580'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/10/time-lapse.html' title='Time Lapse'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-8912432485802837520</id><published>2011-10-23T20:30:00.000-05:00</published><updated>2011-10-23T20:30:35.770-05:00</updated><title type='text'>Formatting Lilypond Sheet Music for the Kindle</title><content type='html'>Tired of fumbling around with my collection of sheet music looking for a certain piece, I thought it would be great to have some sheet music on my third generation kindle (now called the &lt;a href="http://www.amazon.com/gp/product/B004HFS6Z0"&gt;Kindle Keyboard&lt;/a&gt;). I have always been a fan of the open source program &lt;a href="http://lilypond.org/"&gt;Lilypond&lt;/a&gt;. Lilypond is a &lt;a href="http://en.wikipedia.org/wiki/TeX"&gt;TeX&lt;/a&gt;-like system where sheet music is written to a text file and then compiled into the desired output.&lt;br /&gt;Since Lilypond is similar to Tex, Lilypond files have incredible control of the output. No exception is adjusting paper dimensions, only a simple command is required:&lt;br /&gt;&lt;pre&gt;\paper {&lt;br /&gt;   paper-height = H\mm&lt;br /&gt;   paper-width = W\mm&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;where H is the desired height in millimeters and W is the desired width in millimeters of the output paper. Since the kindle was a "fit-to-width" option for PDFs, the first step is to figure out the aspect ratio of the display. Once we have the aspect ratio, then we can configure the scaling to make the actual output legible from a reasonable distance. At first I thought that this would be easy. The Kindle has a resolution of 600x800, or an aspect ratio of 3:4 (the screen is taller than it is wide). However, when creating sheet music of this ratio and the display mode of the Kindle set to "fit-to-width", the pages spanned multiple virtual pages. This meant that the music was cut off between virtual pages. This makes playing the music impossible. From here I decided to figure out the ratio by creating a bunch of files of varying ratios and testing the output.&lt;br /&gt;&lt;br /&gt;It turns out that the Kindle is doing a little fudging on the display and allows a range of display ratios that will appear as one virtual page. From what I observe, any ratio between .57-.61. I tried many variations and it also seems there is some other logic going on in the "fit-to-width" option and determining when to page, but this is a decent rule of thumb to work with. Now that we have a few aspect ratios to work with, I wanted to figure out some nice paper size in absolute terms such that Lilypond will output notes about the same size as normal sheet music.&lt;br /&gt;&lt;br /&gt;At first I tried 100mm x 59mm. As you can see, the notes were extremely large and didn't allow many notes to displayed at once. This would making paging an annoying operation while trying to play the music.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-0CSrXdQjfIg/TqS9wCwSjOI/AAAAAAAAAKc/igZ3wvSb-Ng/s1600/IMG_20111023_181215.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="236" src="http://1.bp.blogspot.com/-0CSrXdQjfIg/TqS9wCwSjOI/AAAAAAAAAKc/igZ3wvSb-Ng/s320/IMG_20111023_181215.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Next I doubled everything. I found 200mm x 122mm appears nice.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-4ZNnUOPrC9U/TqS-A2z4eOI/AAAAAAAAAKo/p1Q-YFS0mgU/s1600/IMG_20111023_181250.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="238" src="http://2.bp.blogspot.com/-4ZNnUOPrC9U/TqS-A2z4eOI/AAAAAAAAAKo/p1Q-YFS0mgU/s320/IMG_20111023_181250.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Compared to actual sheet music, the font is a little small, but completely usable. If you want a bigger font and don't mind paging frequently, I tried the in the between, 150mm x 80mm.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ud1vldyzMeE/TqS-ZZ1dl1I/AAAAAAAAAK0/s59ln0EautA/s1600/IMG_20111023_181236.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="238" src="http://1.bp.blogspot.com/-ud1vldyzMeE/TqS-ZZ1dl1I/AAAAAAAAAK0/s59ln0EautA/s320/IMG_20111023_181236.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;This is the closest to actual size, but fine tuning could be done.&lt;br /&gt;&lt;br /&gt;It is worth noting that while doing this, the "fudge" factor I mentioned earlier, or variability in determining the aspect ratio of the virtual page the Kindle will chose to display, is frustrating. These values I found through trial and error by generating many sheet music files, and looking at all of them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-8912432485802837520?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/8912432485802837520/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=8912432485802837520' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/8912432485802837520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/8912432485802837520'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/10/formatting-lilypond-sheet-music-for.html' title='Formatting Lilypond Sheet Music for the Kindle'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-0CSrXdQjfIg/TqS9wCwSjOI/AAAAAAAAAKc/igZ3wvSb-Ng/s72-c/IMG_20111023_181215.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-3260893554828167268</id><published>2011-10-16T17:38:00.000-05:00</published><updated>2011-10-16T17:38:28.377-05:00</updated><title type='text'>Custom HTML "Widgets" for ASP.NET MVC3</title><content type='html'>I was experimenting with &lt;a href="http://www.asp.net/mvc/mvc3"&gt;ASP.NET MVC3&lt;/a&gt; and found myself in need of some HTML outputted by the Razor engine that would need to be used many times. I wanted to follow the &lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY (Don't Repeat Yourself)&lt;/a&gt; principle by having the HTML appear in one spot and allow me to use it many times. Ideally I wanted something like the builtin HTML "widgets".&lt;p&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;   @Html.DropDownList("DropDownID", Model.Items)&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;The way I accomplished this was &lt;a href="http://msdn.microsoft.com/en-us/library/bb383977.aspx"&gt;extension methods&lt;/a&gt;. Extension methods are an interesting way to add functionality to a class without inheritence. There are drawbacks, such as not being able to access protected members of the base class, but for some cases this is ok.&lt;/p&gt;&lt;p&gt;I decided to use extension methods to add a method to the class that corresponded to the @Html object in the Razor engine. I found out that this class was the HtmlHelper class in the System.Web.Mvc namespace. By extending the HtmlHelper class via extension methods, I was able to achieve my goal of adding a custom widget.&lt;/p&gt;&lt;p&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;namespace MvcHtml&lt;br /&gt;{&lt;br /&gt;   using System.Web.Mvc;&lt;br /&gt;&lt;br /&gt;   public static class ExtensionHtml&lt;br /&gt;   {&lt;br /&gt;      public static MvcHtmlString CustomWidget(this HtmlHelper htmlHelper, string property)&lt;br /&gt;      {&lt;br /&gt;         TagBuilder tagBuilder = new TagBuilder("div");&lt;br /&gt;         tagBuilder.SetInnerText(property);&lt;br /&gt;         return new MvcHtmlString(tagBuilder.ToString());&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;After this little bit of work, we are ready to use the custom widget in our view template just as traditional widgets provided for us.&lt;/p&gt;&lt;p&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;   @Html.CustomWidget("SampleProperty")&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;I hope this helps people understand how Razor is producing HTML from these view files!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-3260893554828167268?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/3260893554828167268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=3260893554828167268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/3260893554828167268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/3260893554828167268'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/10/custom-html-widgets-for-aspnet-mvc3.html' title='Custom HTML &quot;Widgets&quot; for ASP.NET MVC3'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-507270218551709525</id><published>2011-10-05T00:33:00.000-05:00</published><updated>2011-10-05T00:33:49.155-05:00</updated><title type='text'>Combining the Decorator Pattern with the Template Method Pattern</title><content type='html'>Design patterns are exactly that, patterns of design. These patterns have been determined to appear frequently throughout software development. These patterns appear so often that they have become well documented  and given names. I cannot recommend more highly the book &lt;a href="http://en.wikipedia.org/wiki/Design_Patterns"&gt;Design Patterns&lt;/a&gt; by the "Gang of Four" as a resource on the topic of patterns.Recently I came across the need to combine to of the most common patterns, the &lt;a href="http://en.wikipedia.org/wiki/Decorator_pattern"&gt;decorator pattern&lt;/a&gt; and the &lt;a href="http://en.wikipedia.org/wiki/Template_method_pattern"&gt;template method pattern&lt;/a&gt;. I needed multiple implementation of a class to simultaneously coexist, the template method pattern, and I also needed to be able to decorate these classes, the decorator pattern. I noticed that while combining these two patterns, the decorator class behaves just as another class that implements the template method.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;/* The template method */&lt;br /&gt;interface AbstractClass&lt;br /&gt;{&lt;br /&gt;   void Method();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* One implementation */&lt;br /&gt;class ConcreteClass1 : AbstractClass&lt;br /&gt;{&lt;br /&gt;   public void Method()&lt;br /&gt;   {&lt;br /&gt;      System.Console.WriteLine("   ConcreteClass1");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Second implementation */&lt;br /&gt;class ConcreteClass2 : AbstractClass&lt;br /&gt;{&lt;br /&gt;   public void Method()&lt;br /&gt;   {&lt;br /&gt;      System.Console.WriteLine("   ConcreteClass2");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Now comes the decorator, which feels just like any other implementation */&lt;br /&gt;abstract class AbstractClassDecorator : AbstractClass&lt;br /&gt;{&lt;br /&gt;   public AbstractClassDecorator(AbstractClass abstractClass)&lt;br /&gt;   {&lt;br /&gt;      this.abstractClass = abstractClass;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public virtual void Method()&lt;br /&gt;   {&lt;br /&gt;      this.abstractClass.Method();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   protected AbstractClass abstractClass;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Now it becomes time to implement the decorators. The nice thing about the decorator pattern is that it allows you to add decorators simply by extending a class. Here I have two decorators.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;class ConcreteDecoratedAbstractClass1 : AbstractClassDecorator&lt;br /&gt;{&lt;br /&gt;   public ConcreteDecoratedAbstractClass1(AbstractClass abstractClass)&lt;br /&gt;      : base(abstractClass)&lt;br /&gt;   {&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public override void Method()&lt;br /&gt;   {&lt;br /&gt;      this.abstractClass.Method();&lt;br /&gt;      System.Console.WriteLine("   Decorator1");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class ConcreteDecoratedAbstractClass2 : AbstractClassDecorator&lt;br /&gt;{&lt;br /&gt;   public ConcreteDecoratedAbstractClass2(AbstractClass abstractClass)&lt;br /&gt;      : base(abstractClass)&lt;br /&gt;   {&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public override void Method()&lt;br /&gt;   {&lt;br /&gt;      this.abstractClass.Method();&lt;br /&gt;      System.Console.WriteLine("   Decorator2");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;And now that the patterns are in place, all we have to do is simply use them. Because of the decoration and template pattern, we are able to create many possibilities to execute the "same" method. We can decorate or not decorate with any of the decorators, and we have multiple implementations of each method.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;class Program&lt;br /&gt;{&lt;br /&gt;   static void Main(string[] args)&lt;br /&gt;   {&lt;br /&gt;      AbstractClass concrete1 = new ConcreteClass1();&lt;br /&gt;      AbstractClass concrete2 = new ConcreteClass2();&lt;br /&gt;      ConcreteDecoratedAbstractClass1 decorated1Concrete1 = new ConcreteDecoratedAbstractClass1(concrete1);&lt;br /&gt;      ConcreteDecoratedAbstractClass1 decorated1Concrete2 = new ConcreteDecoratedAbstractClass1(concrete2);&lt;br /&gt;      ConcreteDecoratedAbstractClass2 decorated2Concrete1 = new ConcreteDecoratedAbstractClass2(concrete1);&lt;br /&gt;      ConcreteDecoratedAbstractClass2 decorated2Concrete2 = new ConcreteDecoratedAbstractClass2(concrete2);&lt;br /&gt;      ConcreteDecoratedAbstractClass2 decorated21Concrete1 = new ConcreteDecoratedAbstractClass2(decorated1Concrete1);&lt;br /&gt;      /* Et cetra */&lt;br /&gt;&lt;br /&gt;      System.Console.WriteLine("Implementaiton 1");&lt;br /&gt;      concrete1.Method();&lt;br /&gt;&lt;br /&gt;      System.Console.WriteLine("Implementation 2");&lt;br /&gt;      concrete2.Method();&lt;br /&gt;&lt;br /&gt;      System.Console.WriteLine("Implementation 1 decorated by decorator 1");&lt;br /&gt;      decorated1Concrete1.Method();&lt;br /&gt;&lt;br /&gt;      System.Console.WriteLine("Implementation 2 decorated by decorator 1");&lt;br /&gt;      decorated1Concrete2.Method();&lt;br /&gt;&lt;br /&gt;      System.Console.WriteLine("Implementation 1 decorated by decorator 2");&lt;br /&gt;      decorated2Concrete1.Method();&lt;br /&gt;&lt;br /&gt;      System.Console.WriteLine("Implementation 2 decorated by decorator 2");&lt;br /&gt;      decorated2Concrete2.Method();&lt;br /&gt;&lt;br /&gt;      System.Console.WriteLine("Implementation 1 decorated by decorator 1 and decorator 2");&lt;br /&gt;      decorated21Concrete1.Method();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This program outputs&lt;br /&gt;&lt;pre&gt;Implementaiton 1&lt;br /&gt;   ConcreteClass1&lt;br /&gt;Implementation 2&lt;br /&gt;   ConcreteClass2&lt;br /&gt;Implementation 1 decorated by decorator 1&lt;br /&gt;   ConcreteClass1&lt;br /&gt;   Decorator1&lt;br /&gt;Implementation 2 decorated by decorator 1&lt;br /&gt;   ConcreteClass2&lt;br /&gt;   Decorator1&lt;br /&gt;Implementation 1 decorated by decorator 2&lt;br /&gt;   ConcreteClass1&lt;br /&gt;   Decorator2&lt;br /&gt;Implementation 2 decorated by decorator 2&lt;br /&gt;   ConcreteClass2&lt;br /&gt;   Decorator2&lt;br /&gt;Implementation 1 decorated by decorator 1 and decorator 2&lt;br /&gt;   ConcreteClass1&lt;br /&gt;   Decorator1&lt;br /&gt;   Decorator2&lt;br /&gt;&lt;/pre&gt;I hope that this was informative in demonstrating the power of patterns and how they can be combined for even greater utility. Please feel free to comment below.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-507270218551709525?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/507270218551709525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=507270218551709525' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/507270218551709525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/507270218551709525'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/10/combining-decorator-pattern-with.html' title='Combining the Decorator Pattern with the Template Method Pattern'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-6977506224167063383</id><published>2011-08-09T00:27:00.002-05:00</published><updated>2011-08-09T11:03:23.407-05:00</updated><title type='text'>Scrobbler support in DAAP</title><content type='html'>A popular &lt;a href=" http://code.google.com/p/daap-client/issues/detail?id=14"&gt;feature request&lt;/a&gt; for DAAP has been &lt;a href="http://www.last.fm"&gt;Last.fm's&lt;/a&gt; Scrobbler support. Scrobbling is a mechanism that allows Last.fm to know what songs you listen to on your personal devices, such as iPods, computer, or your Android device. This allows Last.fm to personalize which songs to suggest more quickly than normal. Big thanks to my brother Michael for implementing this.&lt;br /&gt;&lt;br /&gt;The feature is pretty straight forward. First, a Scrobbling application must be installed on your device. For this version, Scrobbling has been tested with &lt;a href="http://code.google.com/p/scrobbledroid"&gt;scrobbledroid&lt;/a&gt; and &lt;a href="http://code.google.com/p/a-simple-lastfm-scrobbler/"&gt;A Simple Last.fm Scrobbler&lt;/a&gt;. Next, navigating to the preferences via Menu -&gt; Preferences from the Servers screen presents an option to enable this feature. From now on, your music listening will be relayed to your Scrobbling application which in turn relays that to your Last.fm account! No interaction required.&lt;br /&gt;&lt;br /&gt;You can download DAAP via the android market by&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="https://market.android.com/details?id=org.mult.daap"&gt;The Android Market Application&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Scanning the tag &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-8wsrdFv2hZY/TiydSIFE6bI/AAAAAAAAAJw/filhef8E05s/s1600/DAAP_Media_Player.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="119" src="http://3.bp.blogspot.com/-8wsrdFv2hZY/TiydSIFE6bI/AAAAAAAAAJw/filhef8E05s/s320/DAAP_Media_Player.jpeg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-6977506224167063383?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/6977506224167063383/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=6977506224167063383' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/6977506224167063383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/6977506224167063383'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/08/scrobbler-support-in-daap.html' title='Scrobbler support in DAAP'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-8wsrdFv2hZY/TiydSIFE6bI/AAAAAAAAAJw/filhef8E05s/s72-c/DAAP_Media_Player.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-8156661499395916964</id><published>2011-07-24T17:33:00.000-05:00</published><updated>2011-07-24T17:33:00.641-05:00</updated><title type='text'>Don't forget about DAAP</title><content type='html'>I recently updated some of the Android applications my brother and I have on the market. I left out by far the most popular application that we have. I have now fixed that. The DAAP application last night received a small but very useful bug fix. I expect more features to come out for the application in due time.&lt;br /&gt;&lt;br /&gt;The bug fixed was a user experience (UX) design bug. Take the following scenario for instance: Select a song to play. Upon selection, the notification appears and you are free to continue using your phone for other purposes. Suppose that then you decided to return to the home screen or another application via repeatedly pressing the back button on the phone. You can use your phone, but if you returned to the DAAP application, you would have to re-login. If you clicked the notification, there was no way to return to the song selection screen. Essentially there was no way to return to pick a new song without re-logging in, a time consuming process.&lt;br /&gt;&lt;br /&gt;The fix was easy. I added a new menu option on the media player (the screen viewed after clicking the notification) that allows you to return to the playlists. To prevent overloading of the menu options, I moved the shuffle and repeat buttons onto the screen. They are viewable at all times now. A screenshot below is included for demonstration purposes.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-D3ROxKcJb3E/TiycDBGqR_I/AAAAAAAAAJs/UiOmwq8VDsA/s1600/Player+with+menu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-D3ROxKcJb3E/TiycDBGqR_I/AAAAAAAAAJs/UiOmwq8VDsA/s320/Player+with+menu.png" width="192" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;You can download DAAP via the android market by&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="https://market.android.com/details?id=org.mult.daap"&gt;The Android Market Application&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Scanning the tag &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-8wsrdFv2hZY/TiydSIFE6bI/AAAAAAAAAJw/filhef8E05s/s1600/DAAP_Media_Player.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="119" src="http://3.bp.blogspot.com/-8wsrdFv2hZY/TiydSIFE6bI/AAAAAAAAAJw/filhef8E05s/s320/DAAP_Media_Player.jpeg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-8156661499395916964?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/8156661499395916964/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=8156661499395916964' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/8156661499395916964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/8156661499395916964'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/07/dont-forget-about-daap.html' title='Don&apos;t forget about DAAP'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-D3ROxKcJb3E/TiycDBGqR_I/AAAAAAAAAJs/UiOmwq8VDsA/s72-c/Player+with+menu.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-4195909584727434612</id><published>2011-07-17T19:46:00.002-05:00</published><updated>2011-07-17T21:51:37.548-05:00</updated><title type='text'>Updates to mOTP and Utlimate Search Widget</title><content type='html'>I have finally found some free time to fix things that have been bothering me in my Android applications. That means updates!&lt;br /&gt;&lt;br /&gt;First, I have fixed a minor bug in the mOTP application affecting some users. The bug was a simple oversight when originally implementing profile editing. When editing TOTP profiles with a non-default time interval, the time interval would&amp;nbsp; be listed as default. The fix was simple: pre-populate the spinner similar to how the other fields operate.&lt;br /&gt;&lt;br /&gt;The second update was much more demanding. The Ultimate Search Widget application had no support for custom search providers. For instance, if I wanted to search my blog using the widget, I could not. I was restricted to a predefined list of search providers. Also, if I constantly switched between providers, I would have to scroll through the huge list of providers to find the search provider I wanted.&lt;br /&gt;&lt;br /&gt;I solved the first problem by adding support for custom search providers. Simply fill in the name of the provider, the URL portion that appears before the query, the URL portion that appears after the query, and you are set.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-KwK0ew2PQDU/TiN_OamehrI/AAAAAAAAAJY/xquTMJ7tR_s/s1600/Custom.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-KwK0ew2PQDU/TiN_OamehrI/AAAAAAAAAJY/xquTMJ7tR_s/s320/Custom.png" width="192" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Now this newly created search provider will appear in the list of providers when clicking the icon on the left hand side of the widget!&lt;br /&gt;&lt;br /&gt;To fix the second problem, I added a preference type screen where you may click which providers are to appear in the list. This allows you to remove unused providers and make the widget more useful when frequently switching between search providers.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-tVOtMgwFbgM/TiN_nqkxziI/AAAAAAAAAJc/NLIfjirf9so/s1600/Provider+Selection.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-tVOtMgwFbgM/TiN_nqkxziI/AAAAAAAAAJc/NLIfjirf9so/s320/Provider+Selection.png" width="192" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;You can find both of the newly updated applications in The Android Market:&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="https://market.android.com/details?id=org.cry.otp"&gt;mOTP on The Android Market&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-fL8BDCI68tI/TiOBOmM0V7I/AAAAAAAAAJg/BrLW-JCTfpQ/s1600/mOTP.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="118" src="http://4.bp.blogspot.com/-fL8BDCI68tI/TiOBOmM0V7I/AAAAAAAAAJg/BrLW-JCTfpQ/s320/mOTP.png" width="320" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://market.android.com/details?id=org.miceli.ultimatesearch"&gt;Ultimate Search on The Android Market&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-4_EcOet4TrE/TiODGB085zI/AAAAAAAAAJo/7Cw45BPzp4s/s1600/Ultimate_Search_Widget.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="119" src="http://1.bp.blogspot.com/-4_EcOet4TrE/TiODGB085zI/AAAAAAAAAJo/7Cw45BPzp4s/s320/Ultimate_Search_Widget.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-4195909584727434612?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/4195909584727434612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=4195909584727434612' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4195909584727434612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4195909584727434612'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/07/updates-to-motp-and-utlimate-search.html' title='Updates to mOTP and Utlimate Search Widget'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-KwK0ew2PQDU/TiN_OamehrI/AAAAAAAAAJY/xquTMJ7tR_s/s72-c/Custom.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-4837401773149014581</id><published>2011-01-16T23:34:00.000-06:00</published><updated>2011-01-16T23:34:46.775-06:00</updated><title type='text'>Integrating Doxygen with Autotools</title><content type='html'>For my thesis source code, I desired to have Doxygen documentation automatically generated by make. However, after searching the Internet, I was unable to find a decent tutorial. Luckily after reading the great book that I cannot recommend enough, &lt;a href="http://nostarch.com/autotools.htm"&gt;A Practitioner's Guide to GNU Autoconf, Automake, and Libtool&lt;/a&gt; by John Calcote, I learned a great solution. I intend to outline that solution based off his book.&lt;br /&gt;&lt;br /&gt;The first step is to decide how the process will work. In my case, I wrote documentation for a library that I plan for other developers to use. I want the documentation to be able to be viewed using the man utility. The documentation should be generated when the user runs 'make' and should be installed when the user runs 'make install'. If doxygen is not installed, output a warning message during configuration and do not generate any documentation.&lt;br /&gt;&lt;br /&gt;The first step is to determine if the user has Doxygen installed. We can do this by searching for the Doxygen program using the Autoconf macro &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;AC_CHECK_PROGS&lt;/span&gt;. If Doxygen is not found, output a warning message. We can put all of this logic in an m4 script or in-line in the configure.ac file. For this example, I will just put this in configure.ac:&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;AC_CHECK_PROGS([DOXYGEN], [doxygen])&lt;br /&gt;if test -z "$DOXYGEN";&lt;br /&gt;&amp;nbsp;&amp;nbsp; then AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])&lt;br /&gt;fi&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now in configure.ac, we can check to see if we have Doxygen and if so, add some files to later be processed.&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;AM_CONDITIONAL([HAVE_DOXYGEN], &lt;br /&gt;[test -n "$DOXYGEN"])AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([docs/Doxyfile])])&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We see a mention to 'docs/Doxyfile' above. To any Autotools users, this should outline the next step, to write the 'Doxyfile.in' file. This is a file that will be transformed into 'Doxyfile', which will control how Doxygen generates the documentation. The reason we describe the configuration file in a way that configure modifies it is in case that we want certain properties of the documentation to be configurable. For example, we could add a configure option to optionally generate html documentation, --enable-html-doc for example.&lt;br /&gt;&lt;br /&gt;In the subdirectory docs of the project, we can start by running:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;doxygen -g Doxyfile.in&lt;/div&gt;This generates a template configuration file for Doxygen that we can modify to get our final configuration file. We need to supply the project name, project version, and any other options determined by configure. Change the following properties as below:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;PROJECT_NAME = @PACKAGE_NAME@&lt;br /&gt;PROJECT_NUMBER = @PACKAGE_VERSION@&lt;br /&gt;INPUT = @top_srcdir@&lt;/div&gt;Be sure to change other options that you desire, such as HTML output, man output, etc.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now that we have a configuration file ready to be parsed by configuration script, we need to tell Automake to generate makefiles that have rules to generate the actual documentation. In the docs subdirectory, we can create the 'Makefile.am' file that will be transformed by automake into 'Makefile'. Here is a what it looks like:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;if HAVE_DOXYGEN&lt;br /&gt;directory = $(top_srcdir)/docs/man/man3/&lt;br /&gt;&lt;br /&gt;dist_man_MANS = $(directory)/man_page_1.3 $(directory)/man_page_2.3&lt;br /&gt;$(directory)/man_page_1.3: doxyfile.stamp&lt;br /&gt;$(directory)/man_page_2.3: doxyfile.stamp&lt;br /&gt;&lt;br /&gt;doxyfile.stamp:&lt;br /&gt;&amp;nbsp;&amp;nbsp; $(DOXYGEN) Doxyfile&lt;br /&gt;&amp;nbsp;&amp;nbsp; echo Timestamp &amp;gt; doxyfile.stamp&lt;br /&gt;&lt;br /&gt;CLEANFILES = doxyfile.stamp&lt;br /&gt;&lt;br /&gt;all-local: doxyfile.stamp&lt;br /&gt;clean-local:&lt;br /&gt;&amp;nbsp;&amp;nbsp; rm -rf $(top_srcdir)/docs/man&lt;br /&gt;endif &lt;/div&gt;&lt;br /&gt;Now let's look at this carefully. The first thing that you should notice is that all the rules are only generated if configure set &lt;b&gt;HAVE_DOXYGEN&lt;/b&gt;. We can see in the m4 code above that this is set is Doxygen is found.&lt;br /&gt;&lt;br /&gt;Next we set up a convenience variable &lt;b&gt;directory&lt;/b&gt; to save typing later on. Then we set the man pages that we wish to install when 'make install' is called. We set up a "Product List Variable" dist_man_MANS. This is a normal product list variable with a dist modifier. This means that we want to install these files when we run 'make install'. The man_ portion is the prefix, meaning we want to install these files in the &lt;b&gt;$(mandir)&lt;/b&gt; directory. This is set by configure. The MANS portion of this product list is one of the primaries telling Autoconf which types of files are in this list.&lt;br /&gt;&lt;br /&gt;We need make rules to build these man pages during the make stage. To do this, we make a rule for each man page to be installed, each one depending on a file called doxyfile.stamp. The reason we use one file is because of the one to many relationship between the one doxygen command and the many files generated. We need to be able to determine when we need to generate documentation, but which file do we check for. It doesn't make sense to pick one documentation file at random and check for its existence, so we use this solution.&lt;br /&gt;&lt;br /&gt;The doxyfile.stamp target will generate the documentation by using the &lt;b&gt;$DOXYGEN&lt;/b&gt; file determined by configure and the 'Doxyfile' generated from 'Doxyfile.in'. This target must also generate the doxyfile.stamp file also so future documentation file dependency checks are satisfied.&lt;br /&gt;&lt;br /&gt;Now we need to tell Automake we want these built not at 'make install' time, but at 'make' time. To do this, we use a hook to the normal all target. By making the target all-local, we are making a target that will get executed before the normal all target. Now we are set. Make will install the man pages with the 'make install' command as we use the product list man_MANS with the dist prefix. We just need to handle cleaning up files on make clean. To do this, we add the 'doxyfile.stamp' file to the &lt;b&gt;CLEANFILES&lt;/b&gt; list. This list is automatically cleaned when 'make clean' is run. To remove the directory of man pages is slightly different though. We can't easily remove a directory using the &lt;b&gt;CLEANFILES&lt;/b&gt; variable. We simply hook into clean as we did with all and manually remove the directory.&lt;br /&gt;&lt;br /&gt;Now we are set and ready to go. Please comment on improvements or errors in my guide.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-4837401773149014581?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/4837401773149014581/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=4837401773149014581' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4837401773149014581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4837401773149014581'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2011/01/integrating-doxygen-with-autotools.html' title='Integrating Doxygen with Autotools'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-966923783784506519</id><published>2010-12-01T11:41:00.001-06:00</published><updated>2010-12-09T23:35:00.070-06:00</updated><title type='text'>Network Information</title><content type='html'>Whenever you join a company's, campus's, or employer's wireless network, does it ever feel like it is missing something? For instance, when you go to a cafe and join their wireless, there is a disconnect between the companies offerings (coffee) and the service you just received (wireless connectivity). Earlier in the semester I thought of a system that would bridge this disconnect. The system would provide information about the network which was recently joined. The information could be anything, but should be tailored to the company providing the wireless. An example of this could be the cafe providing information of products, sales, contact information, or privacy information regarding the internet.&lt;br /&gt;&lt;br /&gt;To accomplish this, there would be some server running (could be the router providing internet/wireless) that would store the information to be provided. The information could be stored in anyway, but for me I chose to use XML as there are many parsers available. Here is an example of such an XML file describing the network, and some upcoming events.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background: url(&amp;quot;http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif&amp;quot;) repeat scroll 0% 0% rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"&gt;&lt;code style="color: black; word-wrap: normal;"&gt; &amp;lt;Network&amp;gt;  &lt;br /&gt;   &amp;lt;name&amp;gt;University of New Orleans&amp;lt;/name&amp;gt;  &lt;br /&gt;   &amp;lt;link&amp;gt;http://www.uno.edu&amp;lt;/link&amp;gt;  &lt;br /&gt;   &amp;lt;policy&amp;gt;http://www.uno.edu/NonDiscrimination.asp&amp;lt;/policy&amp;gt;  &lt;br /&gt;   &amp;lt;Events&amp;gt;  &lt;br /&gt;    &amp;lt;Event&amp;gt;  &lt;br /&gt;      &amp;lt;title&amp;gt;Party at the library&amp;lt;/title&amp;gt;  &lt;br /&gt;      &amp;lt;description&amp;gt;Free food&amp;lt;/description&amp;gt;  &lt;br /&gt;      &amp;lt;eventLocation&amp;gt;Library&amp;lt;/eventLocation&amp;gt;  &lt;br /&gt;      &amp;lt;dtstart&amp;gt;1288515600000&amp;lt;/dtstart&amp;gt;  &lt;br /&gt;      &amp;lt;dtend&amp;gt;1288522800000&amp;lt;/dtend&amp;gt;  &lt;br /&gt;    &amp;lt;/Event&amp;gt;  &lt;br /&gt;    &amp;lt;Event&amp;gt;  &lt;br /&gt;      &amp;lt;title&amp;gt;Campus Meeting&amp;lt;/title&amp;gt;  &lt;br /&gt;      &amp;lt;description&amp;gt;Talk with the governor&amp;lt;/description&amp;gt;  &lt;br /&gt;      &amp;lt;eventLocation&amp;gt;Administration building&amp;lt;/eventLocation&amp;gt;  &lt;br /&gt;      &amp;lt;dtstart&amp;gt;1293890400000&amp;lt;/dtstart&amp;gt;  &lt;br /&gt;      &amp;lt;dtend&amp;gt;1293901200000&amp;lt;/dtend&amp;gt;  &lt;br /&gt;    &amp;lt;/Event&amp;gt;  &lt;br /&gt;   &amp;lt;/Events&amp;gt;  &lt;br /&gt; &amp;lt;/Network&amp;gt;  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This XML file describes a campus network that may wish to provide students and other network users of upcoming events, but the idea is clear that other types of information may be presented as described above.&lt;br /&gt;&lt;br /&gt;For one of my classes, I decided to craft this idea into an &lt;a href="http://en.wikipedia.org/wiki/Android_%28operating_system%29"&gt;Android&lt;/a&gt; project. The fun part about this is that I would use service discovery to automatically discover the server on the network providing the information. This is in contrast to perhaps a static network address or some &lt;a href="http://en.wikipedia.org/wiki/DHCP"&gt;DHCP&lt;/a&gt; information similar to DNS information.&lt;br /&gt;&lt;br /&gt;I chose to use &lt;a href="http://en.wikipedia.org/wiki/Zeroconf"&gt;zeroconf&lt;/a&gt; technology for the service discovery as there was an easy to use java version of mDNS (a portion of zeroconf) that I used for &lt;a href="https://code.google.com/p/daap-client/"&gt;DAAP&lt;/a&gt; that works nicely in this situation (well not so nicely, but it works). The idea is that the network server that is providing the information, also registers a service of a network-info service type and clients that join the network request services of the network-info service type that was registered. The server responds and provides the information, which the client displays.&lt;br /&gt;&lt;br /&gt;I created an &lt;a href="http://en.wikipedia.org/wiki/Avahi_%28software%29"&gt;Avahi&lt;/a&gt; XML file describing the service so that it would be automatically broadcast on boot. Avahi is an open source implementation of zeroconf and provides utilities such as this to advertise services. &lt;br /&gt;&lt;br /&gt;&lt;pre&amp;nbsp; style="background: url(&amp;quot;http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif&amp;quot;) repeat scroll 0% 0% rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"&gt;&lt;code style="color: black; word-wrap: normal;"&gt; &amp;lt;?xml version="1.0" standalone='no'?&amp;gt; &amp;nbsp;&amp;lt;!DOCTYPE service-group SYSTEM "avahi-service.dtd"&amp;gt; &amp;nbsp;&amp;lt;service-group&amp;gt; &amp;nbsp;&amp;nbsp; &amp;lt;name&amp;gt;UNO&amp;lt;/name&amp;gt; &amp;nbsp;&amp;nbsp; &amp;lt;service&amp;gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;type&amp;gt;_netfo._tcp&amp;lt;/type&amp;gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;port&amp;gt;9090&amp;lt;/port&amp;gt; &amp;nbsp;&amp;nbsp; &amp;lt;/service&amp;gt; &amp;nbsp;&amp;lt;/service-group&amp;gt; &amp;nbsp;&lt;/code&gt;&lt;/pre&amp;nbsp;&gt;So now that the service is advertised and the information being provided is set up, we just need clients to connect.&lt;br /&gt;&lt;br /&gt;Here are the screenshots of the implementation I wrote for my mobile computing class.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_tB1MyAuGHS8/TPaE_SanmgI/AAAAAAAAAGY/Z11FWqkYqCo/s1600/Network+Info.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/_tB1MyAuGHS8/TPaE_SanmgI/AAAAAAAAAGY/Z11FWqkYqCo/s320/Network+Info.png" width="212" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Screen presented after a server is discovered and information provided.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_tB1MyAuGHS8/TPaE-9xP-SI/AAAAAAAAAGU/TkC_Fna496I/s1600/Event+Info.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/_tB1MyAuGHS8/TPaE-9xP-SI/AAAAAAAAAGU/TkC_Fna496I/s320/Event+Info.png" width="212" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Screen presented when an even was clicked, providing more information.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&amp;nbsp;This is great. Imagine all the possibilities of having information from your network. If there are any great ideas that could take advantage of this, feel free to comment with them! One idea that I came up with after beginning the project is an emergency channel. Take the university campus example for instance. Imagine that campus police spotted an armed individual and wanted to alert everyone in as many ways as possible. They can send mass emergency texts, emails, etc. Using the clients connected and listening to network information could be alerted also. I wrote this quickly for the android application as well.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_tB1MyAuGHS8/TPaE-U2TGTI/AAAAAAAAAGQ/2ypwBqDSyEs/s1600/Emergency+Notification.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/_tB1MyAuGHS8/TPaE-U2TGTI/AAAAAAAAAGQ/2ypwBqDSyEs/s320/Emergency+Notification.png" width="213" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Clients receive a notification upon emergency information becoming available.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_tB1MyAuGHS8/TPaE96XGe8I/AAAAAAAAAGM/lrbkGXYR5HY/s1600/Emergency+Info.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/_tB1MyAuGHS8/TPaE96XGe8I/AAAAAAAAAGM/lrbkGXYR5HY/s320/Emergency+Info.png" width="213" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Information presented when the emergency is clicked.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Ok, so maybe budget cuts aren't as scary as armed individuals, but they are scary!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-966923783784506519?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/966923783784506519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=966923783784506519' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/966923783784506519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/966923783784506519'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/12/network-information.html' title='Network Information'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_tB1MyAuGHS8/TPaE_SanmgI/AAAAAAAAAGY/Z11FWqkYqCo/s72-c/Network+Info.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-684734101129421857</id><published>2010-10-06T23:55:00.004-05:00</published><updated>2011-10-05T00:06:32.556-05:00</updated><title type='text'>Python's any and all in C++</title><content type='html'>When working on some &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; problems with a friend, he used a handy little Python trick called all. Here is a typical use of all:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:python"&gt;&lt;br /&gt;if all([x &amp;gt; 1 for key in some_list]):&lt;br /&gt;   print 'True'  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Simply put, if every element of some_list is greater than 1, then true is returned. Similarly, there is another function called any which returns true is any element in a list is true. I decided to test out my C++ skills and write this. Here is my attempt.&lt;br /&gt;&lt;br /&gt;&lt;pre  class="brush:cpp"&gt;&lt;br /&gt;template&amp;lt;class InputIterator, class UnaryFunction&amp;gt;&lt;br /&gt;   bool all(InputIterator first, InputIterator last, UnaryFunction f) {&lt;br /&gt;   bool allTrue;&lt;br /&gt;   for(allTrue = true; first != last; ++first) {&lt;br /&gt;      if(f(*first) == false) {&lt;br /&gt;         allTrue = false;&lt;br /&gt;         break;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   return allTrue;&lt;br /&gt;}&lt;br /&gt;  &lt;br /&gt;template&amp;lt;class InputIterator, class UnaryFunction&amp;gt;&lt;br /&gt;   bool any(InputIterator first, InputIterator last, UnaryFunction f) {&lt;br /&gt;   bool anyTrue;&lt;br /&gt;   for(anyTrue = false; first != last; ++first) {&lt;br /&gt;      if(f(*first) == true) {&lt;br /&gt;         anyTrue = true;&lt;br /&gt;         break;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   return anyTrue;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now to use these functions, simply use it like any other STL function. Make a function or functor that takes the type of the list, and pass it to the any or all function.&lt;br /&gt;&lt;br /&gt;&lt;pre  class="brush:cpp"&gt;&lt;br /&gt;struct apply {&lt;br /&gt;   bool operator() (int x) {&lt;br /&gt;      if(x &amp;gt; 1) {&lt;br /&gt;         return true;&lt;br /&gt;      }&lt;br /&gt;      return false;&lt;br /&gt;   } &lt;br /&gt;};  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And now we just use it like you would expect.&lt;br /&gt;&lt;br /&gt;&lt;pre  class="brush:cpp"&gt;&lt;br /&gt;int main() {  &lt;br /&gt;   std::vector&amp;lt;int&amp;gt; integers;&lt;br /&gt;&lt;br /&gt;   integers.push_back(0);&lt;br /&gt;   integers.push_back(1);&lt;br /&gt;   integers.push_back(2);&lt;br /&gt;   integers.push_back(3);&lt;br /&gt;   bool result = all(integers.begin(), integers.end(), apply());&lt;br /&gt;   std::cout &amp;lt;&amp;lt; "Result is: " &amp;lt;&amp;lt; result &amp;lt;&amp;lt; std::endl;&lt;br /&gt;   result = any(integers.begin(), integers.end(), apply());&lt;br /&gt;   std::cout &amp;lt;&amp;lt; "Result is: " &amp;lt;&amp;lt; result &amp;lt;&amp;lt; std::endl;&lt;br /&gt;   return 0;&lt;br /&gt; }  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Please give me your comments on what you think.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-684734101129421857?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/684734101129421857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=684734101129421857' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/684734101129421857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/684734101129421857'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/10/pythons-any-and-all-in-c.html' title='Python&apos;s any and all in C++'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-338071152003533397</id><published>2010-09-11T15:03:00.000-05:00</published><updated>2010-09-11T15:03:49.486-05:00</updated><title type='text'>Tire Pressure Monitoring Systems</title><content type='html'>Recently there was a discussion in one of my classes where a student claimed that they read of an attack against the tire pressure monitoring system (TPMS) required in all United States automobiles. They claimed the attack could stop the car, accelerate the car, lock the breaks, or anything else conceivable. I was in disbelief so I did some research and made a presentation for our weekly Information Assurance Research meeting.&lt;br /&gt;&lt;br /&gt;I found that the current attacks on TPMS are very limiting. The researchers were able to turn on and off the tire pressure and general information light, but only temporarily. Most experts agree that a more troubling matter exists with current TPMS implementations; they allow someone to track your car by listening to the wireless sensors in the tires themselves. I argue in my presentation, however, that tracking someone by this means would be more difficult than license plates, car color, car model, car year, car make, or toll tags.&lt;br /&gt;&lt;br /&gt;The presentation also covers the researchers use of cheap hardware to decode the wireless signal. I found this aspect very interested. For those interested, here is the link: &lt;a href="https://docs.google.com/fileview?id=0B-C2C7xM_Tt-MzE5Njg5ODQtNDc2Ny00MDk1LWI1MTUtZjllZGU0NWM4ZmIx&amp;hl=en"&gt;Tire Pressure Monitoring Systems (pdf)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-338071152003533397?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/338071152003533397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=338071152003533397' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/338071152003533397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/338071152003533397'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/09/tire-pressure-monitoring-systems.html' title='Tire Pressure Monitoring Systems'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-2356833466381769903</id><published>2010-08-12T18:05:00.000-05:00</published><updated>2010-08-12T18:05:42.621-05:00</updated><title type='text'>Lesson from a Reference</title><content type='html'>I learned a valuable lesson recently. When implemented TOTP on the OTP Android application, I used the Java reference implementation from the draft RFC document. The outputs matched and I assumed everything was fine. Last week, I was given a heads up through email that&amp;nbsp; TOTP output values were not matching output values of other TOTP implementations. I assumed the other applications were wrong as I followed the true reference implementation.&lt;br /&gt;&lt;br /&gt;I realized, however, that I was wrong. I was incorrectly using the source code by not verifying how the input was specified. The source attached to the document assumed that the ASCII seed had already been transformed into a hexadecimal string. For example, the seed in the reference implementation was "3132333435363738393031323334353637383930" which is the hexadecimal representation of the ASCII string "01234567890123456789". I thought that the long string was supposed to be entered by the user. If I would have though shortly about the ridiculous nature of that number, I may have realized my mistake.&lt;br /&gt;&lt;br /&gt;I have released an update to the market correcting this error and a few other bugs. I fixed the activity stack to behave more in line with other Android applications (I didn't know much at the time of writing the older releases). I also cleaned up some interfaces to behave properly on different screen sizes.&lt;br /&gt;&lt;pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-MTExZTYxYTAtZjk4Mi00MzRjLTlmNjctZmU4MDNkMzJkYTFm&amp;amp;hl=en&amp;amp;authkey=CIuduOUN"&gt;Source Code&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-YWY2MWY5ODEtN2U2Zi00NzMzLTg0ZTQtZDY4NGNhMmMwNThh&amp;amp;hl=en&amp;amp;authkey=CNSWo5EC"&gt;APK Installer&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-2356833466381769903?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/2356833466381769903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=2356833466381769903' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/2356833466381769903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/2356833466381769903'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/08/lesson-from-reference.html' title='Lesson from a Reference'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-6395285692094679415</id><published>2010-08-07T18:08:00.000-05:00</published><updated>2010-08-07T18:08:21.959-05:00</updated><title type='text'>Ultimate Search Widget for Android</title><content type='html'>All major browsers have done it. By providing different search providers, a web browser user is quickly able to search their favorite search engine by selecting the search provider and then the desired query. The Google Search widget or Android is great, except it only searches Google. Frequently I find myself typing search queries with the following pattern: "* Wikipedia," "* IMDB," etc. to quickly bring up the desired page. My brother and I decided it would be great if there was a widget of a similar fashion to the way modern web browsers handle searching. Ultime Search Widget is the result of this labor.&lt;br /&gt;&lt;br /&gt;Ultimate Search widget is an Android widget that installs directly on your home screen and bears a similar appearance to Google's Search widget.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_tB1MyAuGHS8/TF3jYHtbAoI/AAAAAAAAAFk/LecODNCEgUo/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/_tB1MyAuGHS8/TF3jYHtbAoI/AAAAAAAAAFk/LecODNCEgUo/s320/1.png" width="212" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;There is a subtle difference however, the Google favicon to the right. As per modern web browsers, by selecting the favicon, the searcher is able to select which search provider they would like to carry out their search.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_tB1MyAuGHS8/TF3kHnIAn_I/AAAAAAAAAFs/bURGLUn_0EA/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_tB1MyAuGHS8/TF3kHnIAn_I/AAAAAAAAAFs/bURGLUn_0EA/s320/2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;After selecting the search provider, the searcher is able to enter a query. All the features of the Google Search widget are provided, such as voice searching and suggestions.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_tB1MyAuGHS8/TF3l3f8DLeI/AAAAAAAAAF8/Mz8vY1ZLYAs/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_tB1MyAuGHS8/TF3l3f8DLeI/AAAAAAAAAF8/Mz8vY1ZLYAs/s320/3.png" /&gt;&lt;/a&gt;&lt;/div&gt;The current providers:&lt;br /&gt;* Amazon&lt;br /&gt;* Answers&lt;br /&gt;* Bing&lt;br /&gt;* Creative Commons&lt;br /&gt;* Dictionary&lt;br /&gt;* eBay&lt;br /&gt;* IMDB&lt;br /&gt;* Google&lt;br /&gt;* Google Images&lt;br /&gt;* Merriam-Webster&lt;br /&gt;* Wikipedia&lt;br /&gt;* Yahoo!&lt;br /&gt;* Youtube&lt;br /&gt;&lt;br /&gt;Wherever applicable, the search results will be the mobile version of the search provider to improve response times of search queries. The Ultimate Search Widget is available on the Android market for a 99¢.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="market://search?q=pname:org.miceli.ultimatesearch"&gt;Check it out!&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-6395285692094679415?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/6395285692094679415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=6395285692094679415' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/6395285692094679415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/6395285692094679415'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/08/ultimate-search-widget-for-android.html' title='Ultimate Search Widget for Android'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_tB1MyAuGHS8/TF3jYHtbAoI/AAAAAAAAAFk/LecODNCEgUo/s72-c/1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-8378641540583497203</id><published>2010-07-05T22:14:00.000-05:00</published><updated>2010-07-05T22:14:54.864-05:00</updated><title type='text'>Silverlight Resources</title><content type='html'>Recently &lt;a href="http://www.t-mobile.com/"&gt;T-Mobile USA&lt;/a&gt; put up a website &lt;a href="http://www.t-mobileclue.com/"&gt;T-Mobile Clue&lt;/a&gt;&amp;nbsp;to tease the upcoming Samsung Vibrant cell phone.&amp;nbsp;The website displayed a series of tiles covering an image.&amp;nbsp;The tiles would slowly be removed and after four days, the image would be completely revealed. After realizing that the entire page was a &lt;a href="http://en.wikipedia.org/wiki/Silverlight"&gt;Silverlight&lt;/a&gt;&amp;nbsp;application, I decided to attempt to find the obscured image by examining the application using some of my reverse engineering skills picked up last semester.&lt;br /&gt;&lt;br /&gt;I first examined the website's source code to find the actual Silverlight application which can be found &lt;a href="http://www.t-mobileclue.com/ClientBin/T-MobileClue.xap"&gt;here&lt;/a&gt; at the time of writing.&amp;nbsp;Extracting this file would have been difficult if it weren't for Ubuntu assigning a zip icon for it. I simply double clicked the file and extracted the dlls.&lt;br /&gt;&lt;br /&gt;I took the dlls and identified the one that was of importance (T-MobileClue.dll) and examined it in a PE Resource editor.&amp;nbsp;I know realize that .NET Silverlight applications store resources differently than normal PE executables. Luckily there are applications similar to PE resource editors for .NET/Silverlight applications.&lt;br /&gt;&lt;br /&gt;I used a program called &lt;a href="http://www.red-gate.com/products/reflector/"&gt;Reflector&lt;/a&gt;&amp;nbsp;to help go through the decompiled&amp;nbsp;application. I quickly found by examining the source code that the obscured image to be revealed was the resource images/rebus.png.&amp;nbsp;Reflector's resource browser quickly allowed me to open the resource. Sure enough this is the image that was revealed four days later.&amp;nbsp;This was a few days ago so I do not feel bad revealing this information, but I will refrain from posting the rebus.png image here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-8378641540583497203?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/8378641540583497203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=8378641540583497203' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/8378641540583497203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/8378641540583497203'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/07/silverlight-resources.html' title='Silverlight Resources'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-4141095885012630805</id><published>2010-06-15T00:15:00.000-05:00</published><updated>2010-06-15T00:15:20.901-05:00</updated><title type='text'>Proactive Secret Sharing</title><content type='html'>I have been researching proactive secret sharing for my master's thesis quite extensively. I was upset to see that no wikipedia article existed so I created one myself. Check it out!&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Proactive_secret_sharing"&gt;Proactive Secret Sharing on Wikipedia&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-4141095885012630805?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/4141095885012630805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=4141095885012630805' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4141095885012630805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4141095885012630805'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/06/proactive-secret-sharing.html' title='Proactive Secret Sharing'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-4741254518498178072</id><published>2010-06-08T00:12:00.000-05:00</published><updated>2010-06-08T00:12:55.705-05:00</updated><title type='text'>Google Code Project for DAAP Android Client</title><content type='html'>We have used &lt;a href="http://code.google.com/hosting/"&gt;Google Code Project Hosting&lt;/a&gt; to set up a &lt;a href="http://code.google.com/p/daap-client/"&gt;project page &lt;/a&gt;for the Android DAAP client.  This will hopefully keep DAAP from overriding this blog. This move also allows &lt;a href="http://code.google.com/p/daap-client/issues/list"&gt;bugs, feature requests, and issues&lt;/a&gt; to be reported and well maintained. There is also a &lt;a href="http://code.google.com/p/daap-client/source/checkout"&gt;subversion repository&lt;/a&gt; provided by Google which will make handling commits between the two developers much easier. I hope to provide with the &lt;a href="http://code.google.com/p/daap-client/wiki/PageName"&gt;wiki&lt;/a&gt; section useful tutorials that explain some of the features, such as streaming, downloading of songs, queuing, etc. Releases will be posted there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-4741254518498178072?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/4741254518498178072/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=4741254518498178072' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4741254518498178072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4741254518498178072'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/06/google-code-project-for-daap-android.html' title='Google Code Project for DAAP Android Client'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-1779482293970422167</id><published>2010-05-10T18:51:00.000-05:00</published><updated>2010-05-10T18:51:07.562-05:00</updated><title type='text'>DAAP Android Client Updates</title><content type='html'>The first release of the DAAP client for Android had a bit more problems than I would like to admit.  We have been happily working with many users to get the application to work in their situations, and in doing so, we have made the DAAP client far better than it was in its initial release.  The changes below are great:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Major memory optimizations&lt;/li&gt;&lt;li&gt;Minor bandwith optimizations&lt;/li&gt;&lt;li&gt;Automatically detect local shares&lt;/li&gt;&lt;li&gt;Playlist support&lt;/li&gt;&lt;li&gt;Queue support&lt;/li&gt;&lt;li&gt;Rhythmbox as server support&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;By eliminated many buffers that were created very frequently, the DAAP client is now able to handle much larger libraries. It is also easy to navigate thanks to playlist support. Queue support is nice, but the interface is probably in its beta. The auto-detection of local shares is really hit or miss and I can find no reason for it. According to a couple of android bug reports I have found, Android does not support connecting to multicast sockets, but it has worked for me a few times, but not very consistently. This is strange. Streaming will come as soon as I can find a good way to do it in Android without skips and jutters.&lt;br /&gt;&lt;br /&gt;My main point in this post is to get feedback from the users.  Is the DAAP client working for you, and if not, which server are you using?  Are there any suggestions?  Also, if you like the application, please rate it positively.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-YjViOTdhZTQtMzBiNy00ZTkzLWI3MzgtZmM0ODFiZmQxMjFm&amp;hl=en"&gt;Updated Source Code&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-OWU1YWFkNTgtZmQ5Yi00MmZlLTljNjUtYjhmNjBlZGFkYzI0&amp;hl=en"&gt;APK Installer File&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-1779482293970422167?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/1779482293970422167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=1779482293970422167' title='56 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/1779482293970422167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/1779482293970422167'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/05/daap-android-client-updates.html' title='DAAP Android Client Updates'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>56</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-711072288473973859</id><published>2010-04-23T13:03:00.000-05:00</published><updated>2010-04-23T13:03:06.736-05:00</updated><title type='text'>DAAP Media Player released to Android Market</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br /&gt;I am very happy to say that I have published the DAAP Media Player to the Android Market today and should be available for everyone to download! This is an initial release with many planned features to come, but I figured that everyone wanted something to use now. The application uses a heavily modified version of the Java &lt;a href="http://sourceforge.net/projects/getittogether/"&gt;Get It Together&lt;/a&gt; Client that has been stripped down to remove all GUI elements, all external libraries, and the integrated with an Android interface.&amp;nbsp; The media player portion may look familiar because it is a modified version of the default Music player interface from Android.&lt;br /&gt;&lt;br /&gt;We only have one server to test it on, but the application is known to work with a mt-daapd/firefly media server.&amp;nbsp; Please comment on the functionality with other media servers. A google code project may be on the horizon. For more information on DAAP, please refer to wikipedia or my &lt;a href="http://chris-miceli.blogspot.com/2009/12/daap-with-android.html"&gt;previous post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Screenshots: &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_tB1MyAuGHS8/S9HewCR7F4I/AAAAAAAAAFM/6_XpYjqRDgk/s1600/fetching.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/_tB1MyAuGHS8/S9HewCR7F4I/AAAAAAAAAFM/6_XpYjqRDgk/s200/fetching.png" width="133" /&gt;&lt;/a&gt;&lt;a href="http://3.bp.blogspot.com/_tB1MyAuGHS8/S9He0TT2cAI/AAAAAAAAAFU/U-2PPJr3KDg/s1600/playing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/_tB1MyAuGHS8/S9He0TT2cAI/AAAAAAAAAFU/U-2PPJr3KDg/s200/playing.png" width="133" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Downloads:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-NGFlOGFhYTUtN2Y1YS00ZWFmLWFlOWYtZGUyZThlMTA5Yjc0&amp;amp;hl=en"&gt;Source Code&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-YTNiYTYwYTctNTk3ZS00Nzk2LThiZGEtMzY3ZmEwNDcwYjE1&amp;amp;hl=en"&gt;APK Installer File&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-711072288473973859?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/711072288473973859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=711072288473973859' title='29 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/711072288473973859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/711072288473973859'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/04/daap-media-player-released-to-android.html' title='DAAP Media Player released to Android Market'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_tB1MyAuGHS8/S9HewCR7F4I/AAAAAAAAAFM/6_XpYjqRDgk/s72-c/fetching.png' height='72' width='72'/><thr:total>29</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-3197624454615292717</id><published>2010-04-19T11:30:00.000-05:00</published><updated>2010-04-19T11:30:42.486-05:00</updated><title type='text'>TOTP on Android</title><content type='html'>Time-based One-time Password Algorithm is an expansion of the HOTP algorithm that uses time as the "moving counter" instead of a normal counter. Still is draft at the time of publishing, I decided that it would not be too difficult to add this to the mOTP application that is currently in the market.&amp;nbsp; A brief description of TOTP can be found on &lt;a href="http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm"&gt;wikipedia&lt;/a&gt; and the full current specification &lt;a href="http://tools.ietf.org/html/draft-mraihi-totp-timebased-05"&gt;here&lt;/a&gt;. Since I already went through the trouble of making mOTP have a multiple OTP framework, all I had to do was add a class and some error checks in the setup page.&amp;nbsp; I will upload the apks soon, but they are already available on the market.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-ZjZiYmUxM2UtZjA5MC00Y2Q5LTkzMTEtODc1MWRkMzQxMzMy&amp;amp;hl=en"&gt;Source code&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Screenshots: &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_tB1MyAuGHS8/S8yEAPmmg0I/AAAAAAAAAE8/fl_vbTD2Bmo/s1600/totp-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://1.bp.blogspot.com/_tB1MyAuGHS8/S8yEAPmmg0I/AAAAAAAAAE8/fl_vbTD2Bmo/s200/totp-1.png" width="133" /&gt;&lt;/a&gt;&lt;a href="http://3.bp.blogspot.com/_tB1MyAuGHS8/S8yEBtcerTI/AAAAAAAAAFE/wqy_HBUnbAI/s1600/totp-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/_tB1MyAuGHS8/S8yEBtcerTI/AAAAAAAAAFE/wqy_HBUnbAI/s200/totp-2.png" width="133" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-3197624454615292717?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/3197624454615292717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=3197624454615292717' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/3197624454615292717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/3197624454615292717'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/04/totp-on-android.html' title='TOTP on Android'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_tB1MyAuGHS8/S8yEAPmmg0I/AAAAAAAAAE8/fl_vbTD2Bmo/s72-c/totp-1.png' height='72' width='72'/><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-1823328204299037884</id><published>2010-02-26T01:00:00.002-06:00</published><updated>2010-02-26T17:51:59.464-06:00</updated><title type='text'>HOTP on Android</title><content type='html'>I have updated the &lt;a href="http://chris-miceli.blogspot.com/2009/12/mobile-otp-android-client.html"&gt;Android mOTP application&lt;/a&gt; to support the &lt;a href="http://www.ietf.org/rfc/rfc4226.txt"&gt;HOTP&lt;/a&gt; algorithm for One-Time Passwords.&amp;nbsp; This involved implementing HOTP in Java.&amp;nbsp; This was not such a chore thanks to Java's easy to use security tools.&amp;nbsp; However, after writing this from scratch, I realized at the end of the RFC was example source code in Java!&amp;nbsp; I used this reference implementation for the android app.&amp;nbsp; I did have to make a minor change to the reference implementation to support more than 10 digits of output for the generated password.&lt;br /&gt;&lt;br /&gt;After this step was done, all that was required was to add an option to make a profile either a HOTP profile or a mOTP type, edit some database fields, and generate a new layout for the HOTP generation page.&amp;nbsp; The Mobile-OTP application is translated into three languages, English, Traditional Chinese, and Simplified Chinese.&amp;nbsp; A goal of mine was to have all additional strings required for this update to also be translated.&amp;nbsp; I have tried very hard to make this happen.&lt;br /&gt;&lt;br /&gt;I also wanted to implement this change in such a way that if a third OTP comes around the corner (&lt;a href="http://en.wikipedia.org/wiki/S/KEY"&gt;S/Key&lt;/a&gt;), that change wouldn't be so hard.&amp;nbsp; I didn't implement any design patterns per the &lt;a href="http://en.wikipedia.org/wiki/Design_Patterns_%28book%29"&gt;Gang of Four&lt;/a&gt;, the code would not require that many modifications to support another algorithm.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-MmNlZmE2NjctNDc0NS00NGYwLTgxZDctYzc2MjkxODdhNDc1&amp;amp;hl=en"&gt;Source code&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-NTkxZjI0N2YtNGNiNS00MzBjLTk5MTEtNzEwNDU4OTg1MTI5&amp;amp;hl=en"&gt;APK file (installer)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Some screenshots for the visual people (often the first thing I look for when evaluating software):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_tB1MyAuGHS8/S4dw3Wz-UlI/AAAAAAAAAD8/HwsJ8kIHFhE/s1600-h/screenshot1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://1.bp.blogspot.com/_tB1MyAuGHS8/S4dw3Wz-UlI/AAAAAAAAAD8/HwsJ8kIHFhE/s200/screenshot1.png" width="133" /&gt;&lt;/a&gt;&lt;a href="http://4.bp.blogspot.com/_tB1MyAuGHS8/S4dxcNW-juI/AAAAAAAAAEE/ZN3JwgXjNZU/s1600-h/screenshot2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://4.bp.blogspot.com/_tB1MyAuGHS8/S4dxcNW-juI/AAAAAAAAAEE/ZN3JwgXjNZU/s200/screenshot2.png" width="133" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-1823328204299037884?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/1823328204299037884/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=1823328204299037884' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/1823328204299037884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/1823328204299037884'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/02/hotp-on-android.html' title='HOTP on Android'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_tB1MyAuGHS8/S4dw3Wz-UlI/AAAAAAAAAD8/HwsJ8kIHFhE/s72-c/screenshot1.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-2734876593197954726</id><published>2010-01-26T10:11:00.000-06:00</published><updated>2010-01-26T10:11:05.133-06:00</updated><title type='text'>mDNS</title><content type='html'>I have been reading about &lt;a href="http://en.wikipedia.org/wiki/Zero_configuration_networking#Apple.27s_protocol:_Multicast_DNS.2FDNS-SD"&gt;mDNS&lt;/a&gt; in preparation for the DAAP client that is coming along nicely.&amp;nbsp; mDNS is the component of DAAP applications that allows automatic discovery of shares on the local network. mDNS is a portion of Apple's Bonjour (formerly Rendezvous) protocol. The way that mDNS works is by essentially creating a pseudo-distributed &lt;a href="http://en.wikipedia.org/wiki/Domain_Name_System"&gt;DNS&lt;/a&gt; name server on the local network.&amp;nbsp; Whenever a client wants to discover information about which services reside on the local network, that client creates a query to a multicast address.&amp;nbsp; All machines that posses some DNS records will receive this query.&amp;nbsp; The machines that has information regarding that query will reply.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jmdns.sourceforge.net/"&gt;JmDNS&lt;/a&gt; is an implementation of mDNS in Java that is very simple.&amp;nbsp; They have a sample application that fetches information about the network and displays what is discovered graphically.&amp;nbsp; I mimicked this code in an attempt to discover all DAAP servers on the network.&amp;nbsp; I always received information that a DAAP server existed on the network, but when my application attempted to resolve the name of the server, JmDNS would never issue the callback.&amp;nbsp; My application would wait indefinitely for this callback and never know how to talk to the server.&amp;nbsp; This was strange to me as &lt;a href="http://en.wikipedia.org/wiki/Wireshark"&gt;wireshark&lt;/a&gt; showed that mDNS was behaving properly and returning the address when my application was resolving the name.&amp;nbsp; JmDNS was just not issuing the callback.&amp;nbsp; Even more strange was the sample application included in the source would always resolve.&amp;nbsp; I found &lt;a href="http://sourceforge.net/projects/jmdns/forums/forum/324611/topic/3089896"&gt;a thread&lt;/a&gt; on the support forums at sourceforge where someone describes the same problem.&amp;nbsp; They noted that the only difference between their application and the sample one was that they request was issued in a thread.&amp;nbsp; Wrapping just the request for resolving a name in a thread strangely fixes the issue.&amp;nbsp; I filed a bug &lt;a href="https://sourceforge.net/tracker/?func=detail&amp;amp;aid=2940317&amp;amp;group_id=93852&amp;amp;atid=605791"&gt;here&lt;/a&gt;.&amp;nbsp; Now we can move forward and incorporate the great feature of automatic server discover for DAAP into our android client.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-2734876593197954726?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/2734876593197954726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=2734876593197954726' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/2734876593197954726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/2734876593197954726'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2010/01/mdns.html' title='mDNS'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-7771152346235046123</id><published>2009-12-28T02:38:00.004-06:00</published><updated>2010-02-14T13:48:30.702-06:00</updated><title type='text'>Mobile-OTP Android Client</title><content type='html'>My brother and I have recently published an application to the &lt;a href="http://www.android.com/market/"&gt;Android Market&lt;/a&gt; that implements the mimics the &lt;a href="http://motp.sourceforge.net/"&gt;Mobile-OTP&lt;/a&gt;&amp;nbsp;reference implementation.&amp;nbsp; I&amp;nbsp;am proud of this for two reasons:&lt;br /&gt;1.&amp;nbsp;&amp;nbsp;This is my first application into the android market.&lt;br /&gt;2.&amp;nbsp; I believe the features of this applications are better than&amp;nbsp;the other MobileOTP clients I have seen thus far.&lt;br /&gt;&lt;br /&gt;Our implementation allows for multiple profiles; essentially this allows a user to store&amp;nbsp;credentials for multiple servers.&amp;nbsp;&amp;nbsp;Also, instead of remembering codes such as "#**#" to initialize a device, our client has easy to navigate menus that follow traditional Android applications' feel. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Here are some links&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.androlib.com/android.application.org-cry-otp-pxEE.aspx"&gt;Androlib&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-NjdlMGY5OTgtY2JjNy00YzI1LWFlYjUtNjFkZGZhYzU1Nzk4&amp;hl=en"&gt;APK file (installer)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://docs.google.com/leaf?id=0B-C2C7xM_Tt-YTZjNGZmMTQtMGIzYi00ZWE3LTkwNjUtNWQxNWU1ZDNmMWM2&amp;hl=en"&gt;Full Source Code&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-7771152346235046123?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/7771152346235046123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=7771152346235046123' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/7771152346235046123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/7771152346235046123'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2009/12/mobile-otp-android-client.html' title='Mobile-OTP Android Client'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-6320235843561288</id><published>2009-12-20T22:15:00.001-06:00</published><updated>2009-12-20T22:46:57.912-06:00</updated><title type='text'>DAAP with Android</title><content type='html'>I recently set up my router to port forward incoming &lt;a href="http://en.wikipedia.org/wiki/Digital_Audio_Access_Protocol"&gt;DAAP&lt;/a&gt;&amp;nbsp;request to my personal server.&amp;nbsp; Essentially this allows me to listen to all my wonderful music over the internet.&amp;nbsp; There exists a few problems though.&amp;nbsp; iTunes does not allow connecting to DAAP servers that aren't connected on the local network.&amp;nbsp; There are a few windows programs that do this, but just a heads up.&amp;nbsp; Also, My phone currently has no software to allow me to connect to DAAP shares.&lt;br /&gt;&lt;br /&gt;I am considering writing an android application that would allow this.&amp;nbsp; I am still in the research phases though.&amp;nbsp; First off, the software would only be able to access custom daap servers or iTunes applications whose version number is less than 7.2 as the protocol was changed then and no reverse engineering has broke it yet.&amp;nbsp; Perhaps my reverse engineering course can change that, but let's see.&amp;nbsp; Second, I need to be able to make android stream an mp3 file.&amp;nbsp; I found &lt;a href="http://blog.pocketjourney.com/2008/04/04/tutorial-custom-media-streaming-for-androids-mediaplayer/"&gt;this nice blog post&lt;/a&gt;&amp;nbsp;which seems very helpful.&amp;nbsp; Let's see where this goes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-6320235843561288?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/6320235843561288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=6320235843561288' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/6320235843561288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/6320235843561288'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2009/12/daap-with-android.html' title='DAAP with Android'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-1696663030259985805</id><published>2009-10-21T17:31:00.001-05:00</published><updated>2009-10-21T17:32:42.324-05:00</updated><title type='text'>HMAC with gcrypt</title><content type='html'>On my way towards a working RFC4226 implementation, I needed an HMAC implementation.&amp;nbsp; I originally started working on my own, but then I was going to need a working suite of hash functions.&amp;nbsp; Obviously I should use some well-known cryptographic libraries for these hash functions.&amp;nbsp; I found &lt;a href="http://www.gnupg.org/"&gt;libgcrypt&lt;/a&gt;, part of GPG.&amp;nbsp; I didn't expect for some reason to find that HMAC was already implemented in this suite as well.&lt;br /&gt;&lt;br /&gt;I decided to use their HMAC to have better integration with their hash functions and for assured functionality.&amp;nbsp; This turned out to be a good thing because it took lots ot tinkering to get my digest to match &lt;a href="http://tools.ietf.org/html/rfc4231"&gt;RFC 4231&lt;/a&gt;. Skipping the dirty work, here are the important functions (in order):&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; gcry_check_version(GCRYPT_VERSION);&lt;br /&gt;&amp;nbsp;&amp;nbsp; gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN);&lt;br /&gt;&amp;nbsp;&amp;nbsp; gcry_control(GCRYCTL_INIT_SECMEM, 1);&lt;br /&gt;&amp;nbsp;&amp;nbsp; gcry_control(GCRYCTL_RESUME_SECMEM_WARN);&lt;br /&gt;&amp;nbsp;&amp;nbsp; gcry_control(GCRYCTL_INITIALIZATION_FINISHED);&lt;br /&gt;&amp;nbsp;&amp;nbsp; gcry_md_open(&amp;amp;hash_handle_, hash_type,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCRY_MD_FLAG_SECURE| GCRY_MD_FLAG_HMAC);&lt;br /&gt;&amp;nbsp;&amp;nbsp; gcry_md_setkey(hash_handle_, key, key_length);&lt;br /&gt;&amp;nbsp;&amp;nbsp; gcry_md_write(hash_handle_, message, length);&lt;br /&gt;&amp;nbsp;&amp;nbsp; gcry_md_read(hash_handle_, 0);&lt;br /&gt;&lt;br /&gt;The hardest part was getting the key to be correct.&amp;nbsp; I take the hexadecimal description of the key, and convert it to an array of unsigned chars for safety (signedness is notorious for messing up values). This is all it takes (more or less) to get a working HMAC implementation.&amp;nbsp; I arraned things more nicely in preparation for the full-blown RFC 4226 code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-1696663030259985805?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/1696663030259985805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=1696663030259985805' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/1696663030259985805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/1696663030259985805'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2009/10/hmac-with-gcrypt.html' title='HMAC with gcrypt'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-4067651455619752886</id><published>2009-10-20T16:59:00.000-05:00</published><updated>2009-10-20T16:59:11.057-05:00</updated><title type='text'>Unit Testing Not a Panacea</title><content type='html'>I attempted to use unit testing on my recently finished &lt;a href="http://en.wikipedia.org/wiki/HMAC"&gt;HMAC&lt;/a&gt; implementation in an attempt to use what I have been told repeatedly and experienced first hand.&amp;nbsp; I first start by noting that when writing in C, unit testing libraries offer little more than a central block of code where tests should be placed.&amp;nbsp; I looked at some libraries &lt;a href="http://check.sourceforge.net/doc/check_html/check_2.html#SEC3"&gt;here&lt;/a&gt; and they seemed suitable, but for my small HMAC implementation, I just made a function that calls some tests I came up with on the spot.&lt;br /&gt;&lt;br /&gt;Here is where my problems began.&amp;nbsp; Unit tests can only test functionality that you explicitly write.&amp;nbsp; This is all that a programmer could ask for, unless someone implements some &lt;a href="http://en.wikipedia.org/wiki/Finite-state_machine"&gt;FSA&lt;/a&gt; to represent a function.&amp;nbsp; That would work on a small subset of useful functions (regular languages), but that is certainly a tangent.&amp;nbsp; I tested some utility functions I wrote by supplying input and the known output.&amp;nbsp; Example below:&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp; char *ascii_hex; &lt;br /&gt;&amp;nbsp;&amp;nbsp; unsigned char *binary;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ascii_hex = (char *)malloc(4);&lt;br /&gt;&amp;nbsp;&amp;nbsp; ascii_hex[0] = 'A';&lt;br /&gt;&amp;nbsp;&amp;nbsp; ascii_hex[1] = 'B';&lt;br /&gt;&amp;nbsp;&amp;nbsp; ascii_hex[2] = 'C';&lt;br /&gt;&amp;nbsp;&amp;nbsp; ascii_hex[3] = '9';&lt;br /&gt;&amp;nbsp;&amp;nbsp; binary = ascii_hex_to_binary(ascii_hex, 2); /* 2 is size in bytes */&lt;br /&gt;&amp;nbsp;&amp;nbsp; if(binary[0] != 0xAB &amp;amp;&amp;amp; binary[1] != 0xC9)&lt;br /&gt;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; printf("Error, ascii_hex_to_binary didn't work\n");&lt;br /&gt;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;I was happy to know that my test passed, but I realized later that ascii_hex_to_binary was not behaving properly.&amp;nbsp; My test did not check the all possible casess of the input string, especially the one that caused my program to not function correctly. The lesson I suppose would be one test is certainly not enough to check the behavior of a nontrivial function.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-4067651455619752886?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/4067651455619752886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=4067651455619752886' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4067651455619752886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/4067651455619752886'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2009/10/unit-testing-not-panacea.html' title='Unit Testing Not a Panacea'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8639197052884293768.post-2283453005424760552</id><published>2009-10-14T17:44:00.000-05:00</published><updated>2009-10-14T17:44:01.806-05:00</updated><title type='text'>RFC 4226</title><content type='html'>I found &lt;a href="http://www.ietf.org/rfc/rfc4226.txt"&gt;this&lt;/a&gt; when reading about &lt;a href="http://www.openauthentication.org/"&gt;OATH&lt;/a&gt;.&amp;nbsp; I am now working on implementing this in C++ with eclipse using the C++ development tools.&amp;nbsp; I find these are not up to par in comparison with Eclipse's java integration, but there is some utility when compared to vim (certainly not in the text editing field though).&lt;br /&gt;&lt;br /&gt;I first need to implement &lt;a href="http://en.wikipedia.org/wiki/HMAC"&gt;HMAC&lt;/a&gt;.&amp;nbsp; I am going to use the &lt;a href="http://en.wikipedia.org/wiki/Strategy_pattern"&gt;strategy pattern&lt;/a&gt; so that any hash function can be used with my HMAC implementation.&amp;nbsp; Since I am not writing my own hash algorithms though, I will be limited to what &lt;a href="http://www.gnupg.org/related_software/libraries.en.html#lib-libgcrypt"&gt;Libgcrypt&lt;/a&gt; has to offer.&lt;br /&gt;&lt;br /&gt;I noticed some problems though in my wikipedia research, so I corrected what I saw.&amp;nbsp; I noticed that &lt;a href="http://en.wikipedia.org/wiki/Existential_forgery"&gt;Existential forgery&lt;/a&gt; had its own page, where as &lt;a href="http://en.wikipedia.org/wiki/Forgery_%28Cryptography%29"&gt;selective and universal forgery&lt;/a&gt; were on one page.&amp;nbsp; I combined the existential forgery page into the generic forgery page.&amp;nbsp; I then renamed the forgery page to reflect the use of digital signatures as well as macs, so now Forgery (MAC) becomes Forgery (Cryptography).&amp;nbsp; I also added a disambiguation page for &lt;a href="http://en.wikipedia.org/wiki/Forgery_%28disambiguation%29"&gt;Forgery&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8639197052884293768-2283453005424760552?l=chris-miceli.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chris-miceli.blogspot.com/feeds/2283453005424760552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8639197052884293768&amp;postID=2283453005424760552' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/2283453005424760552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8639197052884293768/posts/default/2283453005424760552'/><link rel='alternate' type='text/html' href='http://chris-miceli.blogspot.com/2009/10/rfc-4226.html' title='RFC 4226'/><author><name>Chris Miceli</name><uri>http://www.blogger.com/profile/04265458239161287839</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
