<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
 
 <title>TIM GITTOS - graphics and artificial intelligence geek</title>
 
 <link href="http://www.timgittos.com/" />
 <updated>2012-03-02T14:18:17-08:00</updated>
 <id>http://www.timgittos.com/</id>
 <author>
   <name>Tim Gittos</name>
   <email>info@timgittos.com</email>
 </author>
 
 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/TimGittos" /><feedburner:info uri="timgittos" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
   <title>MIT OCW Linear Algebra - Week 4</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/2KRI7cljQ_c/week-4" />
   <updated>2012-03-02T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-linear-algebra/week-4</id>
   <content type="html">&lt;h2&gt;Computing the Nullspace (Ax = 0)&lt;/h2&gt;
&lt;p&gt;Consider the matrix \(A\):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
  2 &amp;amp; 4 &amp;amp; 6 &amp;amp; 8 \\&lt;br /&gt;
  3 &amp;amp; 6 &amp;amp; 8 &amp;amp; 10&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The means of computing the nullspace is matrix elimination. The difference between this and the row elimination we&amp;#8217;ve done previously, is that this will operate on rectangular matrices, not just square ones, and we&amp;#8217;ll need to possibly deal with \(0\) in the pivot position. Notice that column 2 is not linearly independent, and that row 3 is not linearly independent.&lt;/p&gt;
&lt;p&gt;It is important to note that performing matrix elimination doesn&amp;#8217;t change the nullspace, although it does change the column space. That is, the solution to the equation doesn&amp;#8217;t change.&lt;/p&gt;
&lt;p&gt;Following is matrix elimination to solve the equation: \(Ax = 0\):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
  2 &amp;amp; 4 &amp;amp; 6 &amp;amp; 8 \\&lt;br /&gt;
  3 &amp;amp; 6 &amp;amp; 8 &amp;amp; 10&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \to&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 4 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Notice above that in the \(2,2\) pivot position there is a zero, and that it&amp;#8217;s not possible to perform a row exchange with the row beneath it, because that too has a zero in the pivot position.&lt;/p&gt;
&lt;p&gt;This tells us that the second column is not linearly independent, and that it can be formed by a combination of another column.&lt;/p&gt;
&lt;p&gt;To continue, we consider \(2,3\) to be our pivot position instead:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 4 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This gives us the matrix \(u\). It&amp;#8217;s not upper triangular, but it is in echelon form, which describes the structur of the 0&amp;#8217;s in the matrix. We can see that this matrix has 2 pivots &amp;#8211; this means that it has a rank of 2. That is, the rank of a matrix is the number of pivots.&lt;/p&gt;
&lt;p&gt;The matrix \(u\) has 2 pivot columns. A pivot column is a column that holds a pivot. The other columns, that don&amp;#8217;t hold a pivot, are called free columns. They are called free columns because we can assign any value to the unknowns that correspond to those columns, and solve for the unknowns in the pivot colums.&lt;/p&gt;
&lt;p&gt;For example:&lt;br /&gt;
\[&lt;br /&gt;
  x = \begin{bmatrix}&lt;br /&gt;
  ? \\&lt;br /&gt;
  1 \\&lt;br /&gt;
  ? \\&lt;br /&gt;
  0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We can break out the rows of the matrixs and represent them into their equation form:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  x_1 + 2x_2 + 2x_3 + 2x_4 &amp;amp;= 0 \\&lt;br /&gt;
  2x_3 + 4x_4 &amp;amp;= 0&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;From here, using the numbers we picked for the unkowns, we can perform back substitution, and get:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  2x_3 + 4(0) &amp;amp;= 0 \\&lt;br /&gt;
  x &amp;amp;= 0&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;To solve for \(x_1\):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  x_1 + 2(1) + 2(0) + 2(0) &amp;amp;= 0 \\&lt;br /&gt;
  x_1 + 2 &amp;amp;= 0 \\&lt;br /&gt;
  x_1 &amp;amp;= -2&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The solution to this is a vector in the nullspace:&lt;br /&gt;
\[&lt;br /&gt;
  x = \begin{bmatrix}&lt;br /&gt;
  -2 \\ 1 \\ 0 \\ 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Any multiple of the vector \(x\) will also lie in the nullspace. This describes a line that is in the nullspace.&lt;/p&gt;
&lt;p&gt;We can also flip the position of the 0 and the 1 for the free columns:&lt;br /&gt;
\[&lt;br /&gt;
  x = \begin{bmatrix} ? \\ 0 \\ ? \\ 1 \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;And the result of the back substitution is:&lt;br /&gt;
\[&lt;br /&gt;
  x = \begin{bmatrix} 2 \\ 0 \\ -2 \\ 1 \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
which also lies in the nullspace.&lt;/p&gt;
&lt;p&gt;With two vectors in the nullspace, we can determine the entire nullspace. The nullspace is composed of all the combinations of the two vectors found above, and can be represented as:&lt;br /&gt;
\[&lt;br /&gt;
  c\begin{bmatrix} -2 \\ 1 \\ 0 \\ 0 \end{bmatrix} + d\begin{bmatrix}2 \\ 0 \\ -2 \\ 1\end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;To generalize:&lt;br /&gt;
A matrix \(m \times n\) with a rank of \(r\) will have \(n &amp;#8211; r\) free variables, and it&amp;#8217;s nullspace will be composed of the combinations of \(n &amp;#8211; r\) vectors. You can find these vectors by assigning the value of \(1\) to each free variable while assigning the others a value of \(0\), and performing back substitution. You do this \(n &amp;#8211; r\) times and can derive the nullspace. This is due to the fact that there were only \(r\) equations &amp;#8211; the free variables are the result of non linearly independent equations.&lt;/p&gt;
&lt;p&gt;We can further clean up the matrix \(u\), by expressing it in reduced row echelon form. We will call this matrix \(R\).&lt;br /&gt;
Consider again matrix \(u\):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 4 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Notice the row of zeros &amp;#8211; this comes from the fact that the third row was a combination of the first two rows.&lt;/p&gt;
&lt;p&gt;The reduced row echelon form has zeros both above and below the pivots, and the value of 1 in all the pivots:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 0 &amp;amp; -2 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 4 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
We subtracted the second row from the first to get a 0 above the second pivot. Now we can divide the second row by 2, which won&amp;#8217;t change the solution (as it&amp;#8217;s part of the combination of vectors):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 0 &amp;amp; -2 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 2 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This is the matrix \(R\). Now, we can break out the linear equations, and solve them like we did above:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  x_1 + 2x_2 &amp;#8211; 2x_4 &amp;amp;= 0 \\&lt;br /&gt;
  x_3 + 2x_4 &amp;amp;= 0&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;If we then use the procedure to determine the vectors that define the nullspace:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  x &amp;amp;= \begin{bmatrix}&lt;br /&gt;
    ? \\ 1 \\ ? \\ 0&lt;br /&gt;
  \end{bmatrix} \\&lt;br /&gt;
  x_3 + 2(0) &amp;amp;= 0 \\&lt;br /&gt;
  x_3 &amp;amp;0 0 \\&lt;br /&gt;
  x_1 + 2(1) &amp;#8211; 2(0) &amp;amp;= 0 \\&lt;br /&gt;
  x_1 &amp;amp;= -2&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
which gives us the solution vector:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    -2 \\ 1 \\ 0 \\ 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;and for the other free variable:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  x &amp;amp;= \begin{bmatrix}&lt;br /&gt;
    ? \\ 0 \\ ? \\ 1&lt;br /&gt;
  \end{bmatrix} \\&lt;br /&gt;
  x_3 + 2(1) &amp;amp;= 0 \\&lt;br /&gt;
  x_3 &amp;amp;= -2 \\&lt;br /&gt;
  x_1 + 2(0) &amp;#8211; 2(1) &amp;amp;= 0 \\&lt;br /&gt;
  x_1 = 2&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
which gives us the solution vector:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  2 \\ 0 \\ -2 \\ 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
which as you can see is the solution we arrived at before, with \(Ux = 0\). This equation is called \(Rx = 0\).&lt;/p&gt;
&lt;p&gt;Looking at the matrix \(R\), we can see that the identity matrix I exists in the pivot points. And, that the solution to the pivot unknowns exists in the free variables, but with the signs reversed.&lt;/p&gt;
&lt;p&gt;Let us consider a general reduced row echelon form matrix, assuming that the pivot columns are grouped together. It will look like this:&lt;br /&gt;
\[&lt;br /&gt;
  R = \begin{bmatrix}&lt;br /&gt;
  I &amp;amp; F \\&lt;br /&gt;
  0 &amp;amp; 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
where \(I\) is the identity matrix, and \(F\) are the free variables. There may or may not be a row of zeroes.&lt;br /&gt;
This matrix will have \(r\) pivot rows, \(r\) pivot columns, and \(n &amp;#8211; r\) free columns.&lt;/p&gt;
&lt;p&gt;The nullspace for this general reduced row echelon form matrix can be given by:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    -F \\ I&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
where the columns are the vectors that define the nullspace. These vectors are called the null basis, or the basis of the nullspace.&lt;/p&gt;
&lt;p&gt;Remember that the vectors \(\begin{bmatrix}1 \\ 0 \\ 0 \end{bmatrix}, \begin{bmatrix}0 \\ 1 \\ 0 \end{bmatrix}, \begin{bmatrix} 0 \\ 0 \\ 1 \end{bmatrix}\) form the basis of the 3 dimensional cartesian space.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example&lt;/b&gt;&lt;br /&gt;
Convert the matrix \(A\) to reduced row echelon form, and find the solution for the nullspace.&lt;br /&gt;
\[&lt;br /&gt;
  A = \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 3 \\&lt;br /&gt;
    2 &amp;amp; 4 &amp;amp; 6 \\&lt;br /&gt;
    2 &amp;amp; 6 &amp;amp; 8 \\&lt;br /&gt;
    2 &amp;amp; 8 &amp;amp; 10&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
Performing elimination: &lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 3 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
    0 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
    0 &amp;amp; 4 &amp;amp; 4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \to&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 3 \\&lt;br /&gt;
    0 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
    0 &amp;amp; 4 &amp;amp; 4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \to&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 3 \\&lt;br /&gt;
    0 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
The last matrix is the form \(U\), the upper triangular or row echelon form. This matrix has a rank of 2, with 2 pivot columns and 1 free column. &lt;br /&gt;
To compute the special solutions, we can solve the linear equations by setting the free variable to 1:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  2x_2 + 2(1) &amp;amp;= 0 \\&lt;br /&gt;
  x_2 &amp;amp;= -1 \\&lt;br /&gt;
  x_1 + 2(-1) + 3(1) &amp;amp;= 0 \\&lt;br /&gt;
  x_1 +1 &amp;amp;= 0 \\&lt;br /&gt;
  x_1 &amp;amp;= -1&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
This gives us the special solution of:&lt;br /&gt;
\[&lt;br /&gt;
  x = \begin{bmatrix}&lt;br /&gt;
    -1 \\ -1 \\ 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The nullspace is given by the equation: \(c\begin{bmatrix}-1 \\ -1 \\ 1 \end{bmatrix}\). This is a line in 3 dimensional space.&lt;/p&gt;
&lt;p&gt;We could have continued to reduced row echelon form:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 0&lt;br /&gt;
  \end{bmatrix} \to &lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 1 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
Here we can see the identity matrix come out, and the solutions to the pivot variables, \(\begin{bmatrix}1 \\ 1 \end{bmatrix}\), with signs inverted.&lt;/p&gt;
&lt;h2&gt;Solving Ax = b&lt;/h2&gt;
&lt;p&gt;We will continue using matrix \(A\) to demonstrate how to solve a system of linear equations.&lt;br /&gt;
The following system of equations is the matrix \(A\) in linear equation form:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  x_1 + 2x_2 + 2x_3 + 2x_4 &amp;amp;= b_1 \\&lt;br /&gt;
  2x_1 + 4x_2 + 6x_3 + 8x_4 &amp;amp;= b_2 \\&lt;br /&gt;
  3x_1 + 6x_2 + 8x_3 + 10x_4 &amp;amp;= b_3&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
and remember the 3rd row is the sum of rows 1 &amp;amp; 2 &amp;#8211; it is not independent. Therefore, \(b_3\) is dependent on \(b_1\) and \(b_2\). A solution such as \(\begin{bmatrix}1 \\ 5 \\ 17\end{bmatrix}\) will not solve this system.&lt;/p&gt;
&lt;p&gt;To solve \(A\), we need to reduce this matrix:&lt;br /&gt;
\[&lt;br /&gt;
  {&lt;br /&gt;
    \left[&lt;br /&gt;
    \begin{matrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
    2 &amp;amp; 4 &amp;amp; 6 &amp;amp; 8 \\&lt;br /&gt;
    3 &amp;amp; 6 &amp;amp; 8 &amp;amp; 10&lt;br /&gt;
    \end{matrix}&lt;br /&gt;
    \left|&lt;br /&gt;
    \begin{matrix}&lt;br /&gt;
    b_1 \\ b_2 \\ b_3&lt;br /&gt;
    \end{matrix}&lt;br /&gt;
    \right.&lt;br /&gt;
    \right]&lt;br /&gt;
  }&lt;br /&gt;
  \rightarrow&lt;br /&gt;
  {&lt;br /&gt;
    \left[&lt;br /&gt;
    \begin{matrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 4 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 4&lt;br /&gt;
    \end{matrix}&lt;br /&gt;
    \left|&lt;br /&gt;
    \begin{matrix}&lt;br /&gt;
    b_1 \\ b_2 &amp;#8211; 2b_1 \\ b_3 &amp;#8211; 3b_1&lt;br /&gt;
    \end{matrix}&lt;br /&gt;
    \right.&lt;br /&gt;
    \right]&lt;br /&gt;
  }&lt;br /&gt;
  \rightarrow&lt;br /&gt;
  {&lt;br /&gt;
    \left[&lt;br /&gt;
    \begin{matrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 2 &amp;amp; 2 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 2 &amp;amp; 4 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0&lt;br /&gt;
    \end{matrix}&lt;br /&gt;
    \left|&lt;br /&gt;
    \begin{matrix}&lt;br /&gt;
    b_1 \\ b_2 &amp;#8211; 2b_1 \\ b_3 &amp;#8211; b_2 &amp;#8211; b_1&lt;br /&gt;
    \end{matrix}&lt;br /&gt;
    \right.&lt;br /&gt;
    \right]&lt;br /&gt;
  }&lt;br /&gt;
\]&lt;br /&gt;
The last line of the resultant matrix tells us the solvability condition for matrix \(A\). That is that \(b_3 = b_1 + b_2\). If that doesn&amp;#8217;t hold, then \(b\) is not a solution. This tells us there is a solution to \(A\).&lt;/p&gt;
&lt;p&gt;If we suppose that the \(b\) before elimination is \(\begin{bmatrix} 1 \\ 5 \\ 6 \end{bmatrix} \), then the resultant \(b\) after elimination will be:&lt;br /&gt;
\[&lt;br /&gt;
  b = \begin{bmatrix} 1 \\ 3 \\ 0 \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;To generalize, \(A\) is solvable when \(b\) is in the column space of \(A\), (\(C(A)\)).&lt;/p&gt;
&lt;p&gt;In general, if a combination of rows of \(A\) gives a zero row, the same combination of the entries of \(b\) must give 0.&lt;/p&gt;
&lt;p&gt;To continue finding the complete solution to \(Ax = b\), first we find a single solution by setting all free variables to 0 and then solve \(Ax = b\) for the pivot variables, using the values for \(b\) from above:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    2x_3 + 4(0) &amp;amp;= 3 \\&lt;br /&gt;
    \therefore x_3 &amp;amp;= \frac{3}{2} \\&lt;br /&gt;
    x_1 + 2(0) + 2(\frac{3}{2}) + 2(0) &amp;amp;= 1 \\&lt;br /&gt;
    x_1 + 3 &amp;amp;= 1 \\&lt;br /&gt;
    \therefore x_1 &amp;amp;= -2&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
As we can see, one of the solutions to x is:&lt;br /&gt;
\[&lt;br /&gt;
  x = \begin{bmatrix}&lt;br /&gt;
    -2 \\ 0 \\ \frac{3}{2} \\ 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Now that we have one particular solution, the complete solution will be that particular solution added to all vectors in the nullspace.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The complete for solution for \(A\) (for the given \(b\)) is:&lt;br /&gt;
\[&lt;br /&gt;
  x_{complete} = \begin{bmatrix} -2 \\ 0 \\ \frac{3}{2} \\ 0 \end{bmatrix} &lt;br /&gt;
  + c \begin{bmatrix} -2 \\ 1 \\ 0 \\ 0 \end{bmatrix} + &lt;br /&gt;
  d \begin{bmatrix} 2 \\ 0 \\ -2 \\ 1 \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This result is a 2 dimensional subspace of \(R^4\), that goes through the solution of \(x\) that we found, instead of through the origin.&lt;/p&gt;
&lt;p&gt;Generally, consider an \(m\) by \(n\) matrix \(A\) of rank \(r\). Remember the rank of a matrix is how many pivot columns it has.&lt;br /&gt;
We know that \(r \le m\) and \(r \le n\).&lt;br /&gt;
Full column rank means that \(r = n\). This means that all the columns independent, the columns are all pivot variables, and that there are no free variables, and that the nullspace will only contain the zero vector. The solution to \(Ax = b\) will be unique, if it exists.&lt;br /&gt;
Full row rank means that \(r = m\).  This means that all the rows have pivot variables. This means that we can solve \(Ax = b\) for every \(b\), and that there are \(n &amp;#8211; r\) free variables.&lt;br /&gt;
A matrix that is full rank has \(r = m = n\), and a matrix that is full rank is invertible, it&amp;#8217;s reduced row echelon form is the identity matrix, and there is a unique solution.&lt;/p&gt;
&lt;p&gt;To summarize:&lt;br /&gt;
The rank of a matrix tells you everything about the number of solutions, except what those solutions are.&lt;/p&gt;
&lt;p&gt;When \(r = m = n\) (full rank)&lt;br /&gt;
\[&lt;br /&gt;
  R = I&lt;br /&gt;
\]&lt;br /&gt;
and there is 1 solution to \(Ax = b\)&lt;/p&gt;
&lt;p&gt;When \(r = n &amp;lt; m\) (full column rank)&lt;br /&gt;
\[&lt;br /&gt;
  R = \begin{bmatrix} I \\ 0 \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
and there is 0 or 1 solution to \(Ax = b\)&lt;/p&gt;
&lt;p&gt;When \(r = m &amp;lt; n\) (full row rank)&lt;br /&gt;
\[&lt;br /&gt;
  R = \begin{bmatrix}I &amp;amp; F \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
where \(I\) and \(F\) can be intermingled, and \(I\) will be in pivot columns.&lt;br /&gt;
There are \(\infty\) solutions to \(Ax = b\)&lt;/p&gt;
&lt;p&gt;When \(r &amp;lt; m, r &amp;lt; n\)&lt;br /&gt;
\[&lt;br /&gt;
  R = \begin{bmatrix} I &amp;amp; F \\ 0 &amp;amp; 0 \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
where \(I\) and \(F\) can be intermingled, and \(I\) will be in pivot columns.&lt;br /&gt;
There are 0 or \(\infty\) solutions to \(Ax = b\)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=2KRI7cljQ_c:lK7LPwdtP9w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=2KRI7cljQ_c:lK7LPwdtP9w:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=2KRI7cljQ_c:lK7LPwdtP9w:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=2KRI7cljQ_c:lK7LPwdtP9w:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=2KRI7cljQ_c:lK7LPwdtP9w:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=2KRI7cljQ_c:lK7LPwdtP9w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=2KRI7cljQ_c:lK7LPwdtP9w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/2KRI7cljQ_c" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-linear-algebra/week-4</feedburner:origLink></entry>
 
 <entry>
   <title>Udacity AI for Robotics - Week 2</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/mtjVPjD7SFU/week-2" />
   <updated>2012-02-29T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/udacity-ai-for-robotics/week-2</id>
   <content type="html">&lt;h2&gt;Tracking with Kalman Filters&lt;/h2&gt;
&lt;p&gt;Localization involves orienting a robot in a known environment. When that environment contains moving obstacles, such as other robots, or in the case of a self driving car, pedestrians and other cars, tracking is used to identify those obstacles, and determine how fast they are moving and make predictions about their movements.&lt;/p&gt;
&lt;p&gt;Both Kalman filtering and monte carlo methods can be used for both localization and tracking. &lt;br /&gt;
Kalman filters are a continuous, uni-modal method, while monte carlo is a discrete, multimodal method.&lt;/p&gt;
&lt;p&gt;Later, particle filters will be introduced, which combines both techniques to result in a continuous, multi-modal method.&lt;/p&gt;
&lt;h2&gt;Gaussian distributions&lt;/h2&gt;
&lt;p&gt;Monte carlo localization used a histogram to model the probability the robot was in a given location. This histogram is an approximation to a continuous probability:&lt;br /&gt;
&lt;img src="/images/air/montecarlo.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The Gaussian distribution is another probability distribution. It is characterized by 2 features:&lt;br /&gt;
- the mean, \(\mu\), or the value of the top of the curve&lt;br /&gt;
- the variance, \(\sigma^2\), or the width of the curve.&lt;br /&gt;
&lt;img src="/images/air/gaussian.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;In Kalman filters, the values of \((\mu, \sigma^2)\) will identify the belief state of the location of a given obstacle.&lt;br /&gt;
This belief is modelled with the function:&lt;br /&gt;
\[&lt;br /&gt;
  f(x) = \frac{1}{\sqrt{2 \pi \sigma^2 }} e^{-\frac{1}{2}\frac{(x &amp;#8211; \mu)^2}{\sigma^2}}&lt;br /&gt;
\]&lt;br /&gt;
\(\frac{1}{\sqrt{2 \pi \sigma^2 }}\) is a constant used to normalize the probability.&lt;/p&gt;
&lt;p&gt;Kalman filtering is called a uni-modal method because the Gaussian distribution is uni-modal. This means that it has a single peak in the graph of the distribution. Gaussian distributions are also symmetrical.&lt;/p&gt;
&lt;p&gt;\(\sigma^2\) is a measure of uncertainty, and in the above equation, it acts to normalize the difference of a value and the mean. The larger the \(\sigma^2\), the more uncertain the distribution is.&lt;/p&gt;
&lt;h2&gt;Stages&lt;/h2&gt;
&lt;p&gt;Similar to the process of localization, Kalman filters involve repetition over two stages of execution: measurement updates and prediction updates. In localization, and in Kalman filters, the measurement update process involves Bayes rule and calculating products of probabilities, and the prediction updates involve total probability and convolution. The main difference is the probability distributions used, in that Kalman filters use a Gaussian distribution.&lt;/p&gt;
&lt;h3&gt;Measurement update&lt;/h3&gt;
&lt;p&gt;As in localization, the robot starts with a prior belief state, which in the case of Kalman filters, is a Gaussian distribution. It is typically very uncertain. If the robot reads it&amp;#8217;s sensors, and obtains a new Gaussian distribution that represents what the sensors detected, it needs to multiply those Gaussians together to get the posterier belief state.&lt;br /&gt;
&lt;img src="/images/air/gaussianupdate.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;This is given by the following equation:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{array}{l}&lt;br /&gt;
  \mu&amp;#8217; = \frac{r^2\mu + \sigma^2\nu}{r^2 + \sigma^2} \\&lt;br /&gt;
  {\sigma^2}&amp;#8217; = \frac{1}{\frac{1}{r^2} + \frac{1}{\sigma^2}}&lt;br /&gt;
  \end{array}&lt;br /&gt;
\]&lt;/p&gt;
&lt;h3&gt;Prediction/Motion update&lt;/h3&gt;
&lt;p&gt;Due to the uncertain nature of robot movement, as in localization, when the robot moves, it loses information. In the case of Kalman filters, this means that the new calculated Gaussian belief state has a higher variance than it did before it moved. Otherwise, the move works similar to convolution in localization.&lt;/p&gt;
&lt;p&gt;The update to the Gaussian belief state is given by:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{array}{l}&lt;br /&gt;
  \mu&amp;#8217; = \mu + u \\&lt;br /&gt;
  {\sigma^2}&amp;#8217; = \sigma^2 + r^2 &lt;br /&gt;
  \end{array}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This is saying that the resultant mean is the move distance (\(u\)) plus the old mean, and the resultant variance is the old variance plus the new variance (uncertainty value in the motion).&lt;br /&gt;
This succinctly models the loss of certainty involved in moving.&lt;/p&gt;
&lt;h2&gt;Multivariate Gaussians&lt;/h2&gt;
&lt;p&gt;So far, all discussion has been referring to Kalman filtering in 1-D, or one dimension. Real life Kalman filtering will likely take place in 2-D or even 3-D space. To do filtering in these higher dimensions, multivariate Gaussians are used.&lt;/p&gt;
&lt;p&gt;Multivariate Gaussians differ in that the mean value becomes an array of means, and the variance value becomes an array of covariance values, of \(D \times D \) size, where D is the dimensionality of the matrix.&lt;/p&gt;
&lt;p&gt;For more on multivariate Gaussians, see &lt;a href="http://cs229.stanford.edu/section/gaussians.pdf"&gt;this Stanford handout from the Machine learning class&lt;/a&gt; and my &lt;a href="http://www.timgittos.com/projects/stanford-machine-learning/"&gt;Machine Learning notes, particularly the notes on unsupervised learning.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To design a Kalman filter in higher dimensions, the Kalman filter needs a state transition function and a measurement function.&lt;/p&gt;
&lt;h3&gt;State transition function&lt;/h3&gt;
&lt;p&gt;When updating the state, as per 1-D Kalman filters, the new location is the old location plus the velocity, and the new velocity is the same as the old velocity. This can be represented by the following equation:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix} x&amp;#8217; \\ \dot{x}&amp;#8217; \end{bmatrix} \leftarrow \begin{bmatrix} 1 &amp;amp; 1 \\ 0 &amp;amp; 1 \end{bmatrix} \begin{bmatrix} x \\ \dot{x} \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The matrix is known as F, and will be used in the update equations.&lt;/p&gt;
&lt;h3&gt;Measurement function&lt;/h3&gt;
&lt;p&gt;Making a measurement involves reading the new location of the object. This can be represented by the following equation:&lt;br /&gt;
\[&lt;br /&gt;
  z \leftarrow \begin{bmatrix} 1 &amp;amp; 0 \end{bmatrix} \begin{bmatrix} x \\ \dot{x} \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The row vector is known as H, and will be used in the update equations.&lt;/p&gt;
&lt;h3&gt;Update equations&lt;/h3&gt;
&lt;p&gt;The following image outlines the general approach to Kalman filtering with multivariate Gaussians:&lt;br /&gt;
&lt;img src="/images/air/multivariategaussian.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The first step is the prediction step. To update the prediction, the location needs to be updated, and the uncertainty covariance needs to be updated.&lt;br /&gt;
Updating the location involves multiplying the current belief of the location by the state transition matrix, described above, and adding a motion vector that describes external motion acting on the item.&lt;br /&gt;
After updating the location, the uncertainty covariance matrix needs to be updated.&lt;/p&gt;
&lt;p&gt;The last step is the measurement update step. To update the measurement, the location needs to be updated, and the uncertainty covariance needs to be updated.&lt;br /&gt;
First, calculate the error in the previous prediction to the current measurement. Project the previous uncertainty into the measurement function and add in noise. Calculate the Kalman gain which is a function of the uncertainty. Update the estimate by adding the current value to the Kalman gain influenced error, and update the uncertainty by adding a manipulated Kalman gain value to the existing uncertainty covariance.&lt;/p&gt;
&lt;h2&gt;More information&lt;/h2&gt;
&lt;p&gt;&lt;a href="/files/air/kalman_intro.pdf"&gt;An Introduction to the Kalman Filter&lt;/a&gt;&lt;br /&gt;
&lt;a href="/files/air/maybeck_ch1.pdf"&gt;Stochastic Models, Estimation and Control &amp;#8211; Volume 1, Chapter 1&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://calypso.inesc-id.pt/FCUL/psm/docs/kalman-dan-simon.pdf"&gt;Kalman Filtering&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=mtjVPjD7SFU:rlbsSMM30jI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=mtjVPjD7SFU:rlbsSMM30jI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=mtjVPjD7SFU:rlbsSMM30jI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=mtjVPjD7SFU:rlbsSMM30jI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=mtjVPjD7SFU:rlbsSMM30jI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=mtjVPjD7SFU:rlbsSMM30jI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=mtjVPjD7SFU:rlbsSMM30jI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/mtjVPjD7SFU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/udacity-ai-for-robotics/week-2</feedburner:origLink></entry>
 
 <entry>
   <title>MIT OCW Single Variable Calculus - Week 4</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/oYAJ55QVDdU/week-4" />
   <updated>2012-02-24T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-single-variable-calculus/week-4</id>
   <content type="html">&lt;h2&gt;Exponents&lt;/h2&gt;
&lt;p&gt;To recap from last time, we took the derivative of&lt;br /&gt;
\[&lt;br /&gt;
  a_k = \left(1 &amp;#8211; \frac{1}{k} \right)^k&lt;br /&gt;
\]&lt;br /&gt;
as \(k\) tends to infinity:&lt;br /&gt;
\[&lt;br /&gt;
  \lim_{k \to \infty} a_k = e&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We came to this result by means of the following (abreviated) process:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{array}{l}&lt;br /&gt;
  ln\;a_k \to 1 \qquad \text{as k approaches infinity} \\&lt;br /&gt;
  e^{ln\;a_k} \to e \qquad \text{as k approaches infinity} \\&lt;br /&gt;
  e^{ln\;a_k} = a_k \quad \text{because} e^{ln\;a} = a&lt;br /&gt;
  \end{array}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We then used that to come up with a formula for \(e\):&lt;br /&gt;
\[&lt;br /&gt;
  e = \lim_{k \to \infty} \left( 1 + \frac{1}{k} \right)^k&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We previously covered solving:&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\delta}{\delta x} x^r = r\;x^{r &amp;#8211; 1}&lt;br /&gt;
\]&lt;br /&gt;
for all real r. Now we will cover solving it for all r.&lt;/p&gt;
&lt;p&gt;Method 1: use base e.&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  x^r &amp;amp;= \left(e^{ln\;x} \right)^r\\&lt;br /&gt;
  &amp;amp;= e^{r\;ln\;x} \\&lt;br /&gt;
  \frac{\delta}{\delta x}x^r &amp;amp;= \left( e^{r\;ln\;x} \right)&amp;#8217; \\&lt;br /&gt;
  &amp;amp;= e^{r\;ln\;x}(r\;ln\;x)&amp;#8217; \\&lt;br /&gt;
  &amp;amp;= x^r \frac{r}{x} \\&lt;br /&gt;
  &amp;amp;= r\;x^{r &amp;#8211; 1}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
which shows that it holds for the above.&lt;/p&gt;
&lt;p&gt;Method 2: logarithmic differentiation.&lt;br /&gt;
\[&lt;br /&gt;
  u = x^r, \quad ln\;u = r\;ln\;x&lt;br /&gt;
\]&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{u&amp;#8217;}{u} &amp;amp;= (ln\;u)&amp;#8217; \\&lt;br /&gt;
  &amp;amp;= \frac{r}{x} \\&lt;br /&gt;
  u&amp;#8217; &amp;amp;= u \frac{r}{x} \\&lt;br /&gt;
  &amp;amp;= x^r \frac{r}{x} \\&lt;br /&gt;
  &amp;amp;= r\;x^{r &amp;#8211; 1}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
which shows that it holds for the above.&lt;/p&gt;
&lt;h2&gt;Review&lt;/h2&gt;
&lt;h3&gt;General formulas&lt;/h3&gt;
&lt;p&gt;Practice \((u + v)&amp;#8216;, (c\;u)&amp;#8217;, (u\;v)&amp;#8216;, (\frac{u}{v})&amp;#8217;\), the last two being the product rule and the quotient rule respectively.&lt;br /&gt;
Also know the chain rule:&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\delta}{\delta x}f(u) = f&amp;#8217;(u)\;u&amp;#8217;(x) \qquad \text{where} \quad u = u(x)&lt;br /&gt;
\]&lt;br /&gt;
and implicit differentiation &amp;#8211; inverses, logarithmic differentiation.&lt;/p&gt;
&lt;h3&gt;Specific functions&lt;/h3&gt;
&lt;p&gt;\( x^r, sin\;x, cos\;x, tan\;x, sec\;x, e^x, ln\;x, tan^{-1}x, sin{-1}x \)&lt;/p&gt;
&lt;h3&gt;Chain rule&lt;/h3&gt;
&lt;p&gt;We previously didn&amp;#8217;t explain why the chain rule was true. Now we will show it through an example.&lt;br /&gt;
Take the function: \(y = 10x + b\). \(y\) is changing 10 times as fast as x, therefore \(\frac{\delta y}{\delta x} = 10\).&lt;br /&gt;
Now consider: \(x = 5t + a\), then \(\frac{\delta x}{\delta t} = 5\).&lt;br /&gt;
The chain rule says that if \(y\) is increasing 10 times as fast as \(x\), and \(x\) is increasing 5 times as fast as \(t\), then \(y\) is increasing 50 times as fast as \(t\).&lt;/p&gt;
&lt;p&gt;You can use the chain rule to make other rules easier to use.&lt;br /&gt;
For example, the quotient rule:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  f &amp;amp;= \left( \frac{1}{v} \right) \\&lt;br /&gt;
  f&amp;#8217; &amp;amp;= \left( \frac{1}{v} \right)&amp;#8217; \\&lt;br /&gt;
  &amp;amp;= ( v^{-1} )&amp;#8217; \\&lt;br /&gt;
  &amp;amp;= ( v^{-1} )&amp;#8217; v&amp;#8217; \qquad \text{by the chain rule} \\&lt;br /&gt;
  &amp;amp;= -v^{-2}v&amp;#8217;&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
and the full derrivation of the chain rule:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  f &amp;amp;= \left( \frac{u}{v} \right) \\&lt;br /&gt;
  f&amp;#8217; &amp;amp;= \left( \frac{u}{v} \right)&amp;#8217; \\&lt;br /&gt;
  &amp;amp;= (u\;v^{-1})&amp;#8217; \\&lt;br /&gt;
  &amp;amp;= u&amp;#8217;v^{-1} + u(-v^{-2}v&amp;#8217;) \\&lt;br /&gt;
  &amp;amp;= \frac{(u&amp;#8217;v &amp;#8211; uv&amp;#8217;)}{v^2}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;h3&gt;Examples&lt;/h3&gt;
&lt;p&gt;Consider: \(\frac{\delta}{\delta x} sec\;x\).&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x} sec\;x &amp;amp;= \frac{\delta}{\delta x}(cos\;x)^{-1} \\&lt;br /&gt;
    &amp;amp;= &amp;#8211; (cos\;x)^{-2} cos&amp;#8217;x \\&lt;br /&gt;
    &amp;amp;= &amp;#8211; (cos\;x)^{-2}( -sin\;x) \\&lt;br /&gt;
    &amp;amp;= \frac{sin\;x}{cos^2x} \\&lt;br /&gt;
    &amp;amp;= \frac{1}{cos\;x} \times \frac{sin\;x}{cos\;x} \\&lt;br /&gt;
    &amp;amp;= sec\;x\:tan\;x&lt;br /&gt;
  \end{align}  &lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Generally, when differentiation trig functions, express the answer in terms of the original trig function if at all possible, as we did above.&lt;/p&gt;
&lt;p&gt;Consider: \(\frac{\delta}{\delta x} ln(sec\;x)&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x}ln(sec\;x) &amp;amp;= ln(sec\;x)&amp;#8216;(sec\;x)&amp;#8217; \\&lt;br /&gt;
    &amp;amp;= \frac{1}{sec\;x}(sec\;x)&amp;#8217; \\&lt;br /&gt;
    &amp;amp;= \frac{1}{sec\;x}(sec\;x\;tan\;x) \\&lt;br /&gt;
    &amp;amp;= tan\;x&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Consider: \(\frac{\delta}{\delta x}(x^{10} + 8x)^6\)&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \frac{\delta}{\delta x}(x^{10} + 8x)^6 = 6(x^{10} + 8x)^5(10x^9 + 8)&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We used the chain rule above because expanding the equation out to the 6th power would have taken a lot of space.&lt;/p&gt;
&lt;p&gt;Consider: \(\frac{\delta}{\delta x}e^{x\;tan^{-1}x}\)&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{\delta}{\delta x}e^{x\;tan^{-1}x} &amp;amp;= e^{x\;tan^{-1}x}(x\;tan^{-1}x)&amp;#8217; \\&lt;br /&gt;
  &amp;amp;= e^{x\;tan^{-1}x}(x(tan^{-1}x)&amp;#8217; + tan^{-1}x) \\&lt;br /&gt;
  &amp;amp;= e^{x\;tan^{-1}x}\left(tan^{-1}x + \frac{x}{1 + x^2}\right)&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;h3&gt;Review Continued&lt;/h3&gt;
&lt;p&gt;The definition of the derivative:&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\delta}{\delta x}f(x) = lim_{\Delta x \to 0} \frac{f(x + \Delta x) &amp;#8211; f(x)}{\Delta x}&lt;br /&gt;
\]&lt;br /&gt;
We discovered the derivative of the following functions using the first principles of differentiation:&lt;br /&gt;
\(\frac{1}{x}, x^n, sin\;x, cos\;x \text{last two using} \quad x = 0, a^x, (uv), \left(\frac{u}{v}\right)\)&lt;/p&gt;
&lt;p&gt;We also discussed the meaning of a derivative, that is, the rate of change with respect to some variable.&lt;/p&gt;
&lt;p&gt;You can also read the formula for a derivative backwards, and get the function from the limit:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \lim_{u \to 0}\frac{e^u &amp;#8211; 1}{u} &amp;amp;= \frac{e^{u &amp;#8211; 0} &amp;#8211; e^0}{u} \\&lt;br /&gt;
  &amp;amp;= \frac{\delta}{\delta x}e^u \bigg|_{u = 0} \\&lt;br /&gt;
  &amp;amp;= 1&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;h2&gt;Applications of Differentiation&lt;/h2&gt;
&lt;h3&gt;Linear approximations&lt;/h3&gt;
&lt;p&gt;The formula for linear approximations:&lt;br /&gt;
\[&lt;br /&gt;
  f(x) \approx (fx_0) + f&amp;#8217;(x_0)(x &amp;#8211; x_0)&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This means that if you have a curve, such as \(y = f(x)\), then it is approximately the same as it&amp;#8217;s tangent line, \(y = f(x_0) + f&amp;#8217;(x_0)(x &amp;#8211; x_0)\).&lt;/p&gt;
&lt;p&gt;For example, consider the function \(f(x) = ln\;x\) and it&amp;#8217;s derivative, \(f&amp;#8217;(x) = \frac{1}{x}\), at \(x = 1\):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  f(1) &amp;amp;= ln\;1 = 0 \\&lt;br /&gt;
  f&amp;#8217;(1) &amp;amp;= 1 \\&lt;br /&gt;
  ln\;x &amp;amp;\approx 0 + 1(x &amp;#8211; 1) \\&lt;br /&gt;
  &amp;amp;\approx x &amp;#8211; 1&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This shows that for the function \(ln\;x\), when \(x = 1\), it is approximate to the function \(y = x &amp;#8211; 1\). When \(x\) changes significantly, this is no longer true, and \(ln\;x\) will approximate some other function:&lt;br /&gt;
&lt;img src="/images/svcalc/approx.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Remember the definition of a derivative is the limit as the change in \(x\) goes to zero, of the ratio of the change in the result of the function and the change in \(x\):&lt;br /&gt;
\[&lt;br /&gt;
  f&amp;#8217;(x) = \lim_{\Delta x \to 0} \frac{\Delta f}{\Delta x}&lt;br /&gt;
\]&lt;br /&gt;
You can also look at this backwards, by looking at the limit and determining the derivative based off of that.&lt;/p&gt;
&lt;p&gt;In linear approximation, what we&amp;#8217;re essentially saying is that as \(\Delta x\) gets close to 0:&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\Delta f}{\Delta x} \approx f&amp;#8217;(x_0)&lt;br /&gt;
\]&lt;br /&gt;
That is, the average rate of change (\(\frac{\Delta f}{\Delta x}\)) is close to the infintesimal rate of change (\(f&amp;#8217;(x)\)) as \(x\) approaches some value.&lt;/p&gt;
&lt;p&gt;The formula above is the same as the formula for linear approximation:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\Delta f}{\Delta x} &amp;amp;\approx f&amp;#8217;(x_0) \\&lt;br /&gt;
    \Delta f &amp;amp;\approx f&amp;#8217;(x_0)\Delta x \\&lt;br /&gt;
    f(x) &amp;#8211; f(x_0) &amp;amp;\approx f&amp;#8217;(x_0)(x &amp;#8211; x_0) \\&lt;br /&gt;
    f(x) &amp;amp;\approx f(x_0) + f&amp;#8217;(x_0)(x &amp;#8211; x_0)&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;h3&gt;Systematic discussion of linear approximation&lt;/h3&gt;
&lt;p&gt;When performing a systematic discussion, convention is to use \(x_0 = 0\). This will result in the formula for linear approximation:&lt;br /&gt;
\[&lt;br /&gt;
  f(x) \approx f(0) + f&amp;#8217;(0)x&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Below will be an analysis of the linear approximation of a few notable functions:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{array}{ l | l | l | l | l }&lt;br /&gt;
  f &amp;amp; f&amp;#8217; &amp;amp; f(0) &amp;amp; f&amp;#8217;(0) &amp;amp; f(0) + f&amp;#8217;(0)x \\ \hline&lt;br /&gt;
  sin\;x &amp;amp; cos\;x &amp;amp; 0 &amp;amp; 1 &amp;amp; x \\&lt;br /&gt;
  cos\;x &amp;amp; -sin\;x &amp;amp; 1 &amp;amp; 0 &amp;amp; 1 \\&lt;br /&gt;
  e^x &amp;amp; e^x &amp;amp; 1 &amp;amp; 1 &amp;amp; 1 + x \\&lt;br /&gt;
  ln(1 + x) &amp;amp; \frac{1}{1 + x} &amp;amp; 0 &amp;amp; 1 &amp;amp; x \\&lt;br /&gt;
  (1 + x)^r &amp;amp; r(1 + x)^{r &amp;#8211; 1} &amp;amp; 1 &amp;amp; r &amp;amp; 1 + rx \\&lt;br /&gt;
  \end{array}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;And geometrically:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;\(sin\;x\)&lt;/b&gt;&lt;br /&gt;
&lt;img src="/images/svcalc/approx-sinx.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;\(cos\;x\)&lt;/b&gt;&lt;br /&gt;
&lt;img src="/images/svcalc/approx-cosx.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;\(e^x\)&lt;/b&gt;&lt;br /&gt;
&lt;img src="/images/svcalc/approx-ex.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The last two examples are important. Due to the convention of \(x = 0\), we can&amp;#8217;t find the tangent of \(ln\), because the slope of \(ln(0)\) tends \(-\infty\). The slope of \(x^r\) also tends to \(\infty\). To deal with this, we shift the function by starting from a base of one.&lt;/p&gt;
&lt;p&gt;Going back to our earlier approximation of \(ln\), we can consider the following:&lt;br /&gt;
\[&lt;br /&gt;
  ln\;u \approx u &amp;#8211; 1&lt;br /&gt;
\]&lt;br /&gt;
from above, and just set \(u = 1 + x\) to achieve the approximation at \(x = 0\).&lt;/p&gt;
&lt;h3&gt;Applications of linear approximation&lt;/h3&gt;
&lt;p&gt;Consider the following example:&lt;br /&gt;
\[&lt;br /&gt;
  ln\;1.1 \approx \frac{1}{10}&lt;br /&gt;
\]&lt;br /&gt;
We achieved this by using the rule from above:&lt;br /&gt;
\[&lt;br /&gt;
  ln(1 + x) \approx x&lt;br /&gt;
\]&lt;br /&gt;
and just set \(x = \frac{1}{10}\).&lt;/p&gt;
&lt;p&gt;This only holds because \(x\) is sufficiently small. We work with linear approximations of functions because they are easier to calculate than the functions themselves.&lt;/p&gt;
&lt;p&gt;You can see this in the following examples:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1&lt;/b&gt;&lt;br /&gt;
Find the linear approximation &amp;#8220;near \(x = 0\)&amp;#8221; (\(x \approx 0\)) of:&lt;br /&gt;
\[&lt;br /&gt;
  \frac{e^{-3x}}{\sqrt{1 + x}}&lt;br /&gt;
\]&lt;br /&gt;
We can find this from the formulas and their approximations above:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{e^{-3x}}{\sqrt{1 + x}} &amp;amp;= e^{-3x}(1 + x)^{-\frac{1}{2}} \\&lt;br /&gt;
  &amp;amp;\approx (1 &amp;#8211; 3x)(1 &amp;#8211; \frac{1}{2}x) \\&lt;br /&gt;
  &amp;amp;\approx 1 &amp;#8211; 3x &amp;#8211; \frac{1}{2}x + \frac{3}{2}x^2 \\&lt;br /&gt;
  &amp;amp;\approx 1 &amp;#8211; \frac{7}{2}x&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
Note that we discared the quadratic term \(\frac{3}{2}x^2\), because in the transitions above from the functions to their linear approximations, we already discard a lot of quadratic and exponential information, and we&amp;#8217;re only concerned with a linear approximation. It stands to reason that we discard all quadratic information. Also note that when \(x\) is sufficiently small, any quadratic terms are significantly smaller than the linear terms, and can safely be ignored.&lt;/p&gt;
&lt;p&gt;This is kind of the opposite as big O notation in computer science, where we discard smaller terms because we&amp;#8217;re only interested in the high value approximations.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;This example is intended to be relatively real life, and model something you&amp;#8217;ll come across in real life.&lt;/p&gt;
&lt;p&gt;Consider the surface of the earth, and a satellite in orbit around the earth at velocity \(v\). The satellite is a &lt;span class="caps"&gt;GPS&lt;/span&gt; satellite, and requires keeping time, \(T\). On the earth, from our frame of reference, we have time \(T&amp;#8217;\). Special relatively tells us there will be a time dilation between the times \(T\) and \(T&amp;#8217;\), given by:&lt;br /&gt;
\[&lt;br /&gt;
  T&amp;#8217; = \frac{T}{\sqrt{1 &amp;#8211; \frac{v^2}{c^2}}}&lt;br /&gt;
\]&lt;br /&gt;
where \(v\) is the velocity of the satellite, and \(c\) is the speed of light.&lt;br /&gt;
The goal is to determine the difference between times on the satellite and on the earth, or \(\Delta T\)&lt;/p&gt;
&lt;p&gt;We can solve this by using the approximations above, by setting \(u = \frac{v^2}{c^2}\):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    T&amp;#8217; &amp;amp;= T(1 &amp;#8211; u)^{-\frac{1}{2}} \\&lt;br /&gt;
    &amp;amp;\approx T(1 + \frac{1}{2}\frac{v^2}{c^2})&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;To show how this is real life based, when putting the &lt;span class="caps"&gt;GPS&lt;/span&gt; system into orbit, scientists needed to determine whether or not the time dilation would cause errors. The way the satellites are now, \(v = 4km/s\) and \(c = 3 \times 10^5 km/s\), which means that \(\frac{v^2}{c^2} \approx 10^{-10}\). As you can see, this resolves to an error of a few mm of resolution. Therefore it was determined the dilation wouldn&amp;#8217;t cause significant error.&lt;/p&gt;
&lt;h3&gt;Quadratic approximations&lt;/h3&gt;
&lt;p&gt;The quadratic approximation is an extension of linear approximation. The formula for quadratic approximation is:&lt;br /&gt;
\[&lt;br /&gt;
  f(x) \approx f(x_0) + f&amp;#8217;(x_0)(x &amp;#8211; x_0) + \frac{f&amp;#8217;&amp;#8217;(x)}{2}(x &amp;#8211; x_0)^2&lt;br /&gt;
\]&lt;br /&gt;
As you can see, it involves second derrivatives.&lt;/p&gt;
&lt;p&gt;Now we can extend the common functions we did for linear approximation, and fill them for quadratic approximation:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{array}{ l | l | l | l | l }&lt;br /&gt;
  f &amp;amp; f(0) + f&amp;#8217;(0)x &amp;amp; f&amp;#8217;&amp;#8217; &amp;amp; f&amp;#8217;&amp;#8217;(0) &amp;amp; f(0) + f&amp;#8217;(0)x + \frac{f&amp;#8217;&amp;#8217;(0)}{2}x^2 \\ \hline&lt;br /&gt;
  sin\;x &amp;amp; x &amp;amp; -sin\;x &amp;amp; 0 &amp;amp; x \\&lt;br /&gt;
  cos\;x &amp;amp; 1 &amp;amp; -cos\;x &amp;amp; -1 &amp;amp; 1 &amp;#8211; \frac{1}{2}x^2 \\&lt;br /&gt;
  e^x &amp;amp; 1 + x &amp;amp; e^x &amp;amp; 1 &amp;amp; 1 + x + \frac{1}{2}x^2 \\&lt;br /&gt;
  \end{array}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Geometrically, the significance of the quadratic term can be shown in the following graph:&lt;br /&gt;
&lt;img src="/images/svcalc/quad-approx.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see in the graph, the quadratic approximation is a parabola beneath the linear approximation that more closely fits the cosine wave at \(x = 0\). This tells us more information about the function, such as what it&amp;#8217;s doing on both the positive and negative limits.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oYAJ55QVDdU:jsEGD9z12ZQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oYAJ55QVDdU:jsEGD9z12ZQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=oYAJ55QVDdU:jsEGD9z12ZQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oYAJ55QVDdU:jsEGD9z12ZQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=oYAJ55QVDdU:jsEGD9z12ZQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oYAJ55QVDdU:jsEGD9z12ZQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=oYAJ55QVDdU:jsEGD9z12ZQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/oYAJ55QVDdU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-single-variable-calculus/week-4</feedburner:origLink></entry>
 
 <entry>
   <title>Udacity AI for Robotics - Week 1</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/hpY3ono5gUg/week-1" />
   <updated>2012-02-22T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/udacity-ai-for-robotics/week-1</id>
   <content type="html">&lt;h2&gt;Localization&lt;/h2&gt;
&lt;p&gt;The problem that localization solves is that of determining the robot&amp;#8217;s position to within a 2 &amp;#8211; 10cm precision. Using &lt;span class="caps"&gt;GPS&lt;/span&gt; is not sufficient, as it can have a 2 &amp;#8211; 10m precision, which can result in the robotic car crashing on the side of the road.&lt;/p&gt;
&lt;h3&gt;Conceptual Overview&lt;/h3&gt;
&lt;p&gt;Before getting stuck into the specifics of localization, it will help to get a conceptual overview of what localization does. Localization is a way of modeling where in the environment the robot is.&lt;br /&gt;
This is done by way of computing probabilities of possible locations, in a multi step process that involces reading sensor data from the environment, calculating the belief, moving, recalculating belief and then reading from sensor data again, and recalculating belief.&lt;/p&gt;
&lt;p&gt;The following diagram will illustrate this process, and then it will be explained step by step:&lt;br /&gt;
&lt;img src="/images/air/localization.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;First, we&amp;#8217;re modeling a robot in an environment with 3 doors. The initial belief is called the uniform maximum confusion. This indicates that the robot has absolutely no idea where in the environment it is. It does know what the environment as a whole looks like, however.&lt;/p&gt;
&lt;p&gt;First, it takes a sensor reading from the environment, and detects that it is in front of a door. This reading allows the robot to calculate the probability it is at a given position. As can be seen, it believes it is at one of three positions. Note also that there is a margin of error on the sensors, so there is also a low probability that it could be in a position that is not in front of a door. This is called the posterier belief, because it occurs after a measurement.&lt;/p&gt;
&lt;p&gt;Next, the robot moves a certain distance, and it updates it&amp;#8217;s belief state. This is called a convolution of it&amp;#8217;s belief state. Notice that the probabilities have flattened out somewhat, as there is also a margin of error on the movement. This updated belief state is called the prior belief, because it is a belief before any measurement.&lt;/p&gt;
&lt;p&gt;Lastly, the robot takes another sensor reading of the environment, and detects it is infront of another door. It calculates the probability that it is at a given point, and multiplies it with the prior probability. This has the effect of reinforcing the fact that it saw a door, moved and saw another door. It now strongly believes it&amp;#8217;s currently in front of the second door.&lt;/p&gt;
&lt;p&gt;If it moved, convoluted it&amp;#8217;s belief, and read the environment again and detected another door, then the strong belief that it was in front of the second door would be weakend, representing the fact that the robot could have had a malfunction in movement.&lt;/p&gt;
&lt;h2&gt;Uniform maximum confusion&lt;/h2&gt;
&lt;p&gt;Consider there are 5 discrete locations the robot can be in. The initial uniform maximum confusion will be a uniform probability distributed over the 5 discrete locations, and it will be normalized, meaning it sums to one. Therefore, each location will have a probability of 0.2 of being correct.&lt;/p&gt;
&lt;h2&gt;Posterier update&lt;/h2&gt;
&lt;p&gt;After a measurement, the robot updates the probabilities for each location being considered. The probability in a cell is weighted based on the measurement result. An example of this can be seen below:&lt;br /&gt;
&lt;img src="/images/air/posterierupdate.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;In the above example, the robot observes it is on a red square. The belief state of all red squares is multiplied by 0.6, which is the probability of measuring red, and the belief state of all green squares is multiplied by 0.2, which is the probability of measuring green.&lt;/p&gt;
&lt;p&gt;These probabilities are not valid, however, as they need to be normalized. Here is the result of the normalization:&lt;br /&gt;
&lt;img src="/images/air/posteriernorm.png" alt="" /&gt;&lt;/p&gt;
&lt;h2&gt;Robot Motion&lt;/h2&gt;
&lt;p&gt;When the robot moves, we typically model this action as uncertain. The robot motion may fail for any number of reasons, and so we assign a probability to the success of the motion. In an exact motion model, the probability of motion is 1.&lt;/p&gt;
&lt;p&gt;When motion is uncertain, the robot&amp;#8217;s position in the world itself because even more uncertain:&lt;br /&gt;
&lt;img src="/images/air/inexactmotion.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Everytime the robot moves, it loses information. This is because the movement is uncertain.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Robot localization is a loop of move and sense. When the robot senses, it gains information. When the robot moves, it loses information.&lt;br /&gt;
Here is some python code that demonstrates the concepts discussed above:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='python'&gt;p = [0.2, 0.2, 0.2, 0.2, 0.2]
&lt;p&gt;world = [&amp;#8216;green&amp;#8217;, &amp;#8216;red&amp;#8217;, &amp;#8216;red&amp;#8217;, &amp;#8216;green&amp;#8217;, &amp;#8216;green&amp;#8217;]&lt;br /&gt;
measurements = [&amp;#8216;red&amp;#8217;, &amp;#8216;green&amp;#8217;]&lt;br /&gt;
motions = [1,1]&lt;br /&gt;
pHit = 0.6&lt;br /&gt;
pMiss = 0.2&lt;br /&gt;
pExact = 0.8&lt;br /&gt;
pOvershoot = 0.1&lt;br /&gt;
pUndershoot = 0.1&lt;/p&gt;
&lt;p&gt;def sense(p, Z):&lt;br /&gt;
    q=[]&lt;br /&gt;
    for i in range(len(p)):&lt;br /&gt;
        hit = (Z == world[i])&lt;br /&gt;
        q.append(p[i] * (hit * pHit + (1-hit) * pMiss))&lt;br /&gt;
    s = sum(q)&lt;br /&gt;
    for i in range(len(q)):&lt;br /&gt;
        q[i] = q[i] / s&lt;br /&gt;
    return q&lt;/p&gt;
&lt;p&gt;def move(p, U):&lt;br /&gt;
    q = []&lt;br /&gt;
    for i in range(len(p)):&lt;br /&gt;
        s = pExact * p[(i-U) % len(p)]&lt;br /&gt;
        s = s + pOvershoot * p[(i-U-1) % len(p)]&lt;br /&gt;
        s = s + pUndershoot * p[(i-U+1) % len(p)]&lt;br /&gt;
        q.append(s)&lt;br /&gt;
    return q&lt;/p&gt;
&lt;p&gt;for s, m in zip(measurements, motions):&lt;br /&gt;
    p = sense(p, s)&lt;br /&gt;
    p = move(p, m)&lt;/p&gt;
&lt;p&gt;print p&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Formal Definition&lt;/h2&gt;
&lt;p&gt;The heart of the localization algorithm is probability and Bayes rule. For the formal definition, please see the &lt;a href="/files/ai-class/notes-week-02.pdf"&gt;notes on the Stanford online AI class, specifically Week 2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the above Python code, we applied Bayes rule as follows:&lt;/p&gt;
&lt;p&gt;Assume \(X\) is the collection of grid cells, and \(Z\) is the measurement made.&lt;br /&gt;
\[&lt;br /&gt;
  P(X_i|Z) = \frac{P(Z|X_i) P(X_i)}{P(Z)}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The above represents the following statement in Bayes Rule:&lt;br /&gt;
The probability of being in cell \(X_i\) given measurement \(Z\) can be found by multiplying the probability of measuring \(Z\) while in cell \(X_i\) multiplied by the prior belief that the robot is in \(X_i\), normalized by the probability of observing \(Z\) in any cell.&lt;/p&gt;
&lt;p&gt;We represented it programatically as:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \bar{P}(X_i|Z) &amp;amp;\leftarrow P(Z|X_i) P(X_i) \\&lt;br /&gt;
    \alpha &amp;amp;\leftarrow \sum \bar{P}(X_i|Z) \\&lt;br /&gt;
    P(X_i|Z) &amp;amp;\leftarrow \frac{1}{\alpha} \bar{P}(X_i|Z)&lt;br /&gt;
  \end{align}&lt;br /&gt;
\] &lt;br /&gt;
where \(\alpha\) is the sum of the probabilities of observing \(Z\). This was programmed in the sense function of the Python code above.&lt;/p&gt;
&lt;p&gt;Motion in localization is covered by the concept of total probability:&lt;br /&gt;
\[&lt;br /&gt;
  P(X_i^t) = \sum_j P(X_j^{t-1}) . P(X_i | X_j)&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This says that the probability of being in cell \(X_i\) at time \(t\) is the sum of the probabilities of being in that cell at \(t-1\) times the probability of getting to that cell from any other cells, \(X_j\).&lt;/p&gt;
&lt;p&gt;You can see this programmed into the move function of the Python code above.&lt;/p&gt;
&lt;p&gt;This can be generalized to:&lt;br /&gt;
\[&lt;br /&gt;
  P(A) = \sum_B P(A|B) P(B)&lt;br /&gt;
\]&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=hpY3ono5gUg:UIPSOeC5XgI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=hpY3ono5gUg:UIPSOeC5XgI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=hpY3ono5gUg:UIPSOeC5XgI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=hpY3ono5gUg:UIPSOeC5XgI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=hpY3ono5gUg:UIPSOeC5XgI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=hpY3ono5gUg:UIPSOeC5XgI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=hpY3ono5gUg:UIPSOeC5XgI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/hpY3ono5gUg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/udacity-ai-for-robotics/week-1</feedburner:origLink></entry>
 
 <entry>
   <title>Udacity AI for Robotics</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/LlyJw8WI1C8/udacity-ai-for-robotics" />
   <updated>2012-02-21T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/udacity-ai-for-robotics</id>
   <content type="html">&lt;p&gt;&lt;span class="caps"&gt;THIS&lt;/span&gt; IS A &lt;span class="caps"&gt;PLACEHOLDER&lt;/span&gt; SO &lt;span class="caps"&gt;THAT&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;INDEX&lt;/span&gt; &lt;span class="caps"&gt;APPEARS&lt;/span&gt; IN &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;PROJECT&lt;/span&gt; &lt;span class="caps"&gt;LIST&lt;/span&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=LlyJw8WI1C8:QocD_XI3Vl8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=LlyJw8WI1C8:QocD_XI3Vl8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=LlyJw8WI1C8:QocD_XI3Vl8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=LlyJw8WI1C8:QocD_XI3Vl8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=LlyJw8WI1C8:QocD_XI3Vl8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=LlyJw8WI1C8:QocD_XI3Vl8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=LlyJw8WI1C8:QocD_XI3Vl8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/LlyJw8WI1C8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/udacity-ai-for-robotics</feedburner:origLink></entry>
 
 <entry>
   <title>MIT OCW Linear Algebra - Week 3</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/Bl9Wi8Nwrgw/week-3" />
   <updated>2012-02-18T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-linear-algebra/week-3</id>
   <content type="html">&lt;h2&gt;Permutations&lt;/h2&gt;
&lt;p&gt;Permutation matrices \(P\) execute row exchanges.&lt;/p&gt;
&lt;p&gt;The concept of \(A = LU\), that is, a matrix \(A\) can be factorized into an elimination matrix \(U\) and a set of operations performed during the elimination \(L\). This model supposes no permutations were required during elimination.&lt;/p&gt;
&lt;p&gt;\(PA = LU\) is the description of elimination that takes into account row exchanges, or permutations, occur.&lt;/p&gt;
&lt;h2&gt;Transposes&lt;/h2&gt;
&lt;p&gt;Transposing a matrix:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 3 \\&lt;br /&gt;
  2 &amp;amp; 3 \\&lt;br /&gt;
  4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  ^T&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 4 \\&lt;br /&gt;
  3 &amp;amp; 3 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Generally:&lt;br /&gt;
\[&lt;br /&gt;
  A^T_{i,j} = A_{j,i}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Symmetric matrices are matrices that are the transposes of themselves. That is, \(A^T = A\). Needless to say, a symmetric matrix must be square.&lt;/p&gt;
&lt;p&gt;The product of a matrix and it&amp;#8217;s transpose is a symmetric matrix. \(A^TA\) is always symmetric:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 3 \\&lt;br /&gt;
  2 &amp;amp; 3 \\&lt;br /&gt;
  4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 4 \\&lt;br /&gt;
  3 &amp;amp; 3 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  10 &amp;amp; 11 &amp;amp; 7 \\&lt;br /&gt;
  11 &amp;amp; 13 &amp;amp; 11 \\&lt;br /&gt;
  7 &amp;amp; 11 &amp;amp; 17&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Generally:&lt;br /&gt;
\[&lt;br /&gt;
  (A^TA)^T = A^TA^{TT} = A^TA&lt;br /&gt;
\]&lt;/p&gt;
&lt;h2&gt;Vector spaces &amp;amp; subspaces&lt;/h2&gt;
&lt;p&gt;A vector space is a space, or set of vectors that allow us to take linear combinations of vectors, and multiply vectors by any scalar, and perform vector addition.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Examples:&lt;/b&gt;&lt;br /&gt;
\(R^2\) is a space of all 2-dimension real vectors. Such as \( \begin{bmatrix}3 \\ 2 \end{bmatrix}, \begin{bmatrix}0\\0\end{bmatrix}, \begin{bmatrix}\pi\\e\end{bmatrix}\). This is also known as the x-y plane.&lt;/p&gt;
&lt;p&gt;\(R^3\) is a space of all 3-dimensional real vectors, similar to above, that is, 3 real compents.&lt;/p&gt;
&lt;p&gt;Generally, \(R^n\) is the space of all vectors with \(n\) real numbers.&lt;/p&gt;
&lt;p&gt;Let us imagine the vector space \(R^2\), only lets define it only for positive components. This reduces the vector space to \(\frac{1}{4}\) of it&amp;#8217;s normal size. Consider the task of multiplying a vector by the scalar \(-1\). This would produce a result that is undefined for this restriction. Therefore, this restriction is not a vector space, as it doesn&amp;#8217;t satisfy the rules of a space. That is, it&amp;#8217;s not closed under multiplication of real numbers.&lt;/p&gt;
&lt;p&gt;Imagining the same vector space \(r^2\), and inside this space we have a vector. Lets say we restrict our space to only linear combinations of our vector. That is, we can make our vector as long as as short as we want, and can add and subtract vectors that lie on the same line as the original vector. By that definition, we have defined a vector space inside \(R^2\), called a subspace of \(R^2\). Note, to be a valid subspace, it must contain 0. Therefore the line must pass through the origin in our \(R^2\) space.&lt;br /&gt;
Note, that the subspace of \(R^2\) is not \(R^1\) &amp;#8211; the vectors still contain 2 components.&lt;/p&gt;
&lt;p&gt;Subspaces of \(R^2\):&lt;br /&gt;
1. all of \(R^2\). A space is a subspace of itself.&lt;br /&gt;
2. any line through the point \(\begin{bmatrix}0\\0\end{bmatrix}\).&lt;br /&gt;
3. the zero vector only &amp;#8211; \(Z\)&lt;/p&gt;
&lt;p&gt;Lets apply this concept of subspaces to matrices.&lt;/p&gt;
&lt;p&gt;Consider the matrix A:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 3 \\&lt;br /&gt;
  2 &amp;amp; 3 \\&lt;br /&gt;
  4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The columns of this matrix and all their combinations form a subspace. This is called the column space, \(C(A)\).&lt;br /&gt;
Note this is a subspace of \(R^3\), because each column is \(R^3\), and they form a plane.&lt;/p&gt;
&lt;p&gt;The union of two subspaces does not make a subspace in itself. If you add a vector from one subspace to another vector from a different subspace may result in a vector that lies outside the union of subspaces.&lt;/p&gt;
&lt;p&gt;However, the intersection of two subspaces is a subspace. Consider two subspaces, \(S\) and \(T\), and two vectors in the intersection of those subspaces, \(v\) and \(u\). If \(v\) and \(u\) are both in \(S\), and \(S\) is a subspace, then \(v+u\) will also be in \(S\). Likewise, \(v\) and \(u\) are both in \(T\), and \(T\) is a subspace, therefore \(v+u\) will be in \(T\). This shows that the intersection of \(S\) and \(T\) is a subspace.&lt;/p&gt;
&lt;h2&gt;Column Space&lt;/h2&gt;
&lt;p&gt;Column space of matrix \(A\):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 1 &amp;amp; 2 \\&lt;br /&gt;
  2 &amp;amp; 1 &amp;amp; 3 \\&lt;br /&gt;
  3 &amp;amp; 1 &amp;amp; 4\\&lt;br /&gt;
  4 &amp;amp; 1 &amp;amp; 5&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The column space of \(A\) is a subspace of \(R^4\), because \(A\) is a \(4 \times 3\) matrix. It contains:&lt;br /&gt;
- The columns of \(A\)&lt;br /&gt;
- All linear combinations of the columns of \(A\)&lt;br /&gt;
- The zero vector&lt;br /&gt;
The column subspace is itself a subspace of \(R^4\).&lt;/p&gt;
&lt;p&gt;To answer how we know that, we need to reframe our purpose in studying linear algebra.&lt;br /&gt;
The purpose of studying linear algebra is to understand the equation:&lt;br /&gt;
\[&lt;br /&gt;
  Ax = b&lt;br /&gt;
\]&lt;br /&gt;
and to know if, there is a solution to this equation for ever \(b\).&lt;/p&gt;
&lt;p&gt;There is not a solution for every \(b\), because if you look at A, you can see there are 4 equations with only 3 unknowns:&lt;br /&gt;
\[&lt;br /&gt;
  Ax = &lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 1 &amp;amp; 2 \\&lt;br /&gt;
  2 &amp;amp; 1 &amp;amp; 3 \\&lt;br /&gt;
  3 &amp;amp; 1 &amp;amp; 4 \\&lt;br /&gt;
  4 &amp;amp; 1 &amp;amp; 5&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  x_1 \\&lt;br /&gt;
  x_2 \\&lt;br /&gt;
  x_3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  b_1 \\&lt;br /&gt;
  b_2 \\&lt;br /&gt;
  b_3 \\&lt;br /&gt;
  b_4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
This is because the linear combinations of the columns of \(A\) won&amp;#8217;t fill all of \(R^4\).&lt;/p&gt;
&lt;p&gt;However, there are some solutions, and all of these solutions lie in the column space, that is, they are linear combinations of the columns of \(A\).&lt;/p&gt;
&lt;p&gt;Note that all the columns of \(A\) are not linearly independent &amp;#8211; column 3 is linearly dependent on columns 1 &amp;amp; 2, and column 1 is linearly dependent on 2 &amp;amp; 3. We can get rid of either column 1 or column 3 (but not both) and not lose information about the column space.&lt;br /&gt;
Therefore, the column space is actually a subspace in \(R^2\) of \(R^4\).&lt;/p&gt;
&lt;h2&gt;Nullspace&lt;/h2&gt;
&lt;p&gt;Lets consider again the matrix \(A\), above.&lt;/p&gt;
&lt;p&gt;The null space of \(A\) contains all solutions \(x\), as above, to the equation:&lt;br /&gt;
\[&lt;br /&gt;
  Ax = 0&lt;br /&gt;
\]&lt;br /&gt;
That is, all vectors that nulify the matrix \(A\).&lt;/p&gt;
&lt;p&gt;The nullspace is a subspace of \(R^3\), because there are only 3 unknowns, as you can see by looking at \(x\).&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  Ax = &lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 1 &amp;amp; 2 \\&lt;br /&gt;
  2 &amp;amp; 1 &amp;amp; 3 \\&lt;br /&gt;
  3 &amp;amp; 1 &amp;amp; 4 \\&lt;br /&gt;
  4 &amp;amp; 1 &amp;amp; 5&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  x_1 \\&lt;br /&gt;
  x_2 \\&lt;br /&gt;
  x_3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  0 \\&lt;br /&gt;
  0 \\&lt;br /&gt;
  0 \\&lt;br /&gt;
  0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;One solution to the above equation is:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 \\ 1 \\ -1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;br /&gt;
and in fact, the definition of the nullspace of \(A\) is any combination of the above vector, or:&lt;br /&gt;
\[&lt;br /&gt;
  c&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 \\ 1 \\ -1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The nullspace of \(A\) is a subspace of \(R^3\) and forms a line.&lt;/p&gt;
&lt;p&gt;We can prove that the solutions to \(Ax = 0\) always give a subspace algebraically:&lt;br /&gt;
if \(Av = 0\) and \(Aw = 0\), then \(A(v + w) = 0\). We can restart \(A(v + w) = 0\) as \(Av + Aw = 0\). \(0 + 0 = 0\) will always hold, therefore the solutions to \(Ax = 0\) will always give a subspace.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Bl9Wi8Nwrgw:WRoZvjUw3XM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Bl9Wi8Nwrgw:WRoZvjUw3XM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Bl9Wi8Nwrgw:WRoZvjUw3XM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Bl9Wi8Nwrgw:WRoZvjUw3XM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Bl9Wi8Nwrgw:WRoZvjUw3XM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Bl9Wi8Nwrgw:WRoZvjUw3XM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Bl9Wi8Nwrgw:WRoZvjUw3XM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/Bl9Wi8Nwrgw" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-linear-algebra/week-3</feedburner:origLink></entry>
 
 <entry>
   <title>MIT OCW Single Variable Calculus - Week 3</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/5mgRHqltB58/week-3" />
   <updated>2012-02-17T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-single-variable-calculus/week-3</id>
   <content type="html">&lt;h2&gt;Implicit differentiation&lt;/h2&gt;
&lt;p&gt;Implicit differentiation is a technique that allows you to differentiate functions that you may not have even been able to see.&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \frac{\delta}{\delta x}x^2 = ax^{a-1}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;So far we&amp;#8217;ve covered the case where \(a\) is an integer: \(a = 0, \pm 1, \pm 2, \ldots \). Now we&amp;#8217;re going to consider the case where \(a\) is a rational number: \( a = \frac{m}{n}\), where m &amp;amp; n are integers.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    y &amp;amp;= x^{\frac{m}{n}} \qquad \text{(1)} \\&lt;br /&gt;
    y^n &amp;amp;= x^m \qquad \text{(2)}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Now, we apply \(\frac{\delta}{\delta x}\) to equation (2). We don&amp;#8217;t apply to equation (1) because right now, we don&amp;#8217;t know how to differentiate it. We do know how to differentiate (2).&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x} y^n &amp;amp;= \frac{\delta}{\delta x}x^m \\&lt;br /&gt;
    \left( \frac{\delta}{\delta y}y^n \right) \frac{\delta y}{\delta x} &amp;amp;= mx^{m-1} \qquad \text{(by the chain rule)} \\&lt;br /&gt;
    ny^{n-1}\frac{\delta y}{\delta x} &amp;amp;= mx^{m-1} \\&lt;br /&gt;
    \frac{\delta y}{\delta x} &amp;amp;= \frac{m x^{m &amp;#8211; 1}}{n y^{n &amp;#8211; 1}} \\&lt;br /&gt;
    &amp;amp;= \frac{m}{n} \frac{x^{m-1}}{(x^\frac{m}{n})^{n-1}} \\&lt;br /&gt;
    &amp;amp;= a x^{m-1-(n-1)\frac{m}{n}} \\&lt;br /&gt;
    &amp;amp;= a x^{m-1-m+\frac{m}{n}} \\&lt;br /&gt;
    &amp;amp;= a x^{-1 + \frac{m}{n}} \\&lt;br /&gt;
    &amp;amp;= a x^{a-1} &lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;: &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;CHAIN&lt;/span&gt; &lt;span class="caps"&gt;RULE&lt;/span&gt; &lt;span class="caps"&gt;WILL&lt;/span&gt; &lt;span class="caps"&gt;CAUSE&lt;/span&gt; &lt;span class="caps"&gt;YOU&lt;/span&gt; &lt;span class="caps"&gt;ISSUES&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  x^2 + y^2 = 1&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This is defining \(y\) as a function of \(x\) implictily. That means it can be arranged to express \(y\) in terms of \(x\).&lt;/p&gt;
&lt;p&gt;Solving for y:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    y^2 &amp;amp;= 1 &amp;#8211; x^2 \\&lt;br /&gt;
    y &amp;amp;= \pm \sqrt{1 &amp;#8211; x^2} \\&lt;br /&gt;
    y &amp;amp;= (1-x^2)^{\frac{1}{2}} \qquad \text{considering positive branch only} \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= \frac{1}{2}(1 &amp;#8211; x^2)^{-\frac{1}{2}}(-2x) \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= (1 &amp;#8211; x^2)^{-\frac{1}{2}}(-x) \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= \frac{-x}{\sqrt{1 &amp;#8211; x^2}}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The above is the explicit differentiation. &lt;br /&gt;
Following is the implicit method:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x} (x^2 + y^2 &amp;amp;= 1) \\&lt;br /&gt;
    2x + 2yy&amp;#8217; &amp;amp;= 0 \qquad \text{(by the chain rule)} \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= -\frac{2x}{2y} \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= -\frac{x}{y} \\&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The result of the explicit and implicit methods are the same, and the implicit is better than the explicit because it doesn&amp;#8217;t differentiate between positive and negative values for \(y\) and \(x\).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 3&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Consider the equation \(y^4 + xy^2 &amp;#8211; 2 = 0\).&lt;/p&gt;
&lt;p&gt;We can solve it explicitly: (using the &lt;a href="http://www.purplemath.com/modules/sqrquad2.htm"&gt;quadratic forumula&lt;/a&gt; )&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    y^2 &amp;amp;= \frac{-x \pm \sqrt{x^2 &amp;#8211; 4(-2)}}{2} \\&lt;br /&gt;
    y &amp;amp;= \pm \sqrt{\frac{-x \pm \sqrt{x^2+8}}{2}} \\&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Notice the 4 different roots of the equation (because it&amp;#8217;s to the 4th power).&lt;br /&gt;
It&amp;#8217;s very complex and time consuming.&lt;/p&gt;
&lt;p&gt;Compare this to the implicit method:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x}(y^4 + xy^2 -2 = 0) \\&lt;br /&gt;
    4y^3y&amp;#8217; + y^2 + x(2yy&amp;#8217;) &amp;#8211; 0 &amp;amp;= 0 \\&lt;br /&gt;
    (4y^3 + 2xy)y&amp;#8217; + y^2 &amp;amp;= 0 \\&lt;br /&gt;
    (4y^3 + 2xy)y&amp;#8217; &amp;amp;= -y^2 \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= \frac{-y^2}{4y^3 + 2xy}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;To solve \(y&amp;#8217;\) in terms of x, we&amp;#8217;d need to put the result of the explicit method (so far) into the implicit method. The two go hand in hand.&lt;br /&gt;
Although the implicit method hides the conplexity of solving a quartic equation, it still exists, and at some point, we&amp;#8217;re going to have to deal with it. That means going through all possible 4 roots to find the answer.&lt;/p&gt;
&lt;h2&gt;Inverse functions&lt;/h2&gt;
&lt;p&gt;The inverse of a function is the function that gets us back to our original arguments. For example:&lt;br /&gt;
\[&lt;br /&gt;
  y = \sqrt{x} \text{for x \gt 0}, y^2 = x&lt;br /&gt;
\]&lt;br /&gt;
if we define these in terms of functions:&lt;br /&gt;
\[&lt;br /&gt;
  f(x) = \sqrt{x}, g(y) = x, g(y) = y^2&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;In general:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{array}{2,1}&lt;br /&gt;
  y = f(x), g(y) = x \\&lt;br /&gt;
  g(f(x)) = x, g = f^{-1}, f = g^{-1}&lt;br /&gt;
  \end{array}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Consider the case of graphing a function and it&amp;#8217;s inverse. The inverse can be obtained by swapping the \(x\) and \(y\) values, which in effect is mirroring the function along the line \(x = y\).&lt;br /&gt;
&lt;img src="/images/svcalc/inverse.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Implicit differentiation allows us to find the derivative of any inverse function, provided we know the derivative of the function.&lt;/p&gt;
&lt;p&gt;Example 1:&lt;/p&gt;
&lt;p&gt;Consider the function:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  y = tan^{-1}x&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;which can be rearranged/simplified by taking \(tan\) of each side:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  tan\;y = x&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This can be graphed as follows:&lt;br /&gt;
&lt;img src="/images/svcalc/inverse-tan.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Recall that&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{\delta}{\delta y} tan\;y &amp;amp;= \frac{\delta}{\delta y} \frac{sin\;y}{cos\;y} \\&lt;br /&gt;
  &amp;amp;= \frac{1}{cos^2y}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x} (tan\;y &amp;amp;= x) \\&lt;br /&gt;
    (\frac{\delta}{\delta y} tan\;y)\frac{\delta y}{\delta x} &amp;amp;= 1 \\&lt;br /&gt;
    \frac{1}{cos^2y} y&amp;#8217; &amp;amp;= 1 \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= cos^2y&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Where we apply \(\frac{\delta}{\delta x}\) to both sides (thats why the x turns into a 1). However, we wanted to find \(\frac{\delta}{\delta x}tan^{-1}x\). We can simplify this by expressing \(cos\;y\) in terms of it&amp;#8217;s defining ratio:&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/svcalc/tan-ratio.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;which shows us the hypotenuse is \(\sqrt{1 + x^2}\). This gives us:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  cos\;y &amp;amp;= \frac{1}{\sqrt{1 + x^2}} \\&lt;br /&gt;
  cos^2y &amp;amp;= \frac{1}{1 + x^2}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;and then we substitute in the above:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{\delta}{\delta x}tan^{-1}x &amp;amp;= cos^2(tan^{-1}x) \\&lt;br /&gt;
  &amp;amp;= \frac{1}{1 + x^2}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Example 2:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    y &amp;amp;= sin^{-1}x \\&lt;br /&gt;
    sin y &amp;amp;= x \\&lt;br /&gt;
    (cos\;y)y&amp;#8217; &amp;amp;= 1 \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= \frac{1}{cos\;y} \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= \frac{1}{\sqrt{1 &amp;#8211; sin^2y}} \\&lt;br /&gt;
    y&amp;#8217; &amp;amp;= \frac{1}{\sqrt{1 &amp;#8211; x^2}} \\&lt;br /&gt;
    \therefore \frac{\delta}{\delta x}sin^{-1}x &amp;amp;= \frac{1}{\sqrt{1 &amp;#8211; x^2}}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;h2&gt;Exponentials &amp;amp; Logarithms&lt;/h2&gt;
&lt;p&gt;First, lets review exponents.&lt;br /&gt;
Consider some base, \(a\), such that \(a &amp;gt; 0\). We know that \(a^0 = 0\), \(a^1 = a\), \(a^2 = a \times a\). Generally:&lt;br /&gt;
\[&lt;br /&gt;
  a^{x_1 + x_2} = a^{x_1}a^{x_2}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This is known as the law of exponents. From this we can derive:&lt;br /&gt;
\[&lt;br /&gt;
  (a^{x_1})^{x_2} = a^{x_1x_2}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Likewise:&lt;br /&gt;
\[&lt;br /&gt;
  a^{\frac{m}{n}} = \sqrt[n]{a^m}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;\(a^x\) is defined for all x by continuity. We can calculate things like \(a^\pi\) and \(a^{\sqrt{2}}\) using the rules above.&lt;/p&gt;
&lt;p&gt;Example graph of \(y = 2^x\):&lt;br /&gt;
&lt;img src="/images/svcalc/exp.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;WThe ultimate goal is to be able to solve&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\delta}{\delta x}a^x&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We can begin by going back to first principles:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{\delta}{\delta x}a^x &amp;amp;= \lim_{\Delta x \to 0} \frac{a^{x + \Delta x} &amp;#8211; a^x}{\Delta x} \\ &lt;br /&gt;
  &amp;amp;= \lim_{\Delta x \to 0} \frac{a^x a^{\Delta x} &amp;#8211; a^x}{\Delta x} \\&lt;br /&gt;
  &amp;amp;= \lim_{\Delta x \to 0} a^x \frac{a^{\Delta x} &amp;#8211; 1}{\Delta x} \\&lt;br /&gt;
  &amp;amp;= a^x \lim_{\Delta x \to 0} \frac{a^{\Delta x} &amp;#8211; 1}{\Delta x}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We move the \(a^x\) out of the limit, because as the limit tends to 0, \(a^x\) is constant, and can be moved out of the limit.&lt;br /&gt;
Next, lets define a new variable, and express the above equation in a new way:&lt;br /&gt;
\[&lt;br /&gt;
  M(a) = \lim_{\Delta x \to 0} \frac{a^{\Delta x} &amp;#8211; 1}{\Delta x}&lt;br /&gt;
\]&lt;br /&gt;
so that&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\delta}{\delta x}a^x = M(a)a^x&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;If we recall back to the start of the course, we can recognise that as the equation of a line, the tangent line. From here, we can work out the slope of \(a^x\). First, plug in \(a = 0\) to the above:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \left. \frac{\delta}{\delta x}a^x \right|_{x = 0} &amp;amp;= M(a)a^0 \\&lt;br /&gt;
  &amp;amp;= M(a)&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;So we can see that the slope of \(a^x\) at \(x = 0\) is \(M(a)\). What is \(M(a)\)? &lt;br /&gt;
Solving \(M(a)\) is difficult. Lets beg the question, and instead, define \(e\) as the number such that \(M(e) = 1\).&lt;br /&gt;
The consequences of having a number such as \(e\) are as follows:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{\delta}{\delta x}e^x &amp;amp;= M(e)e^x \\&lt;br /&gt;
  &amp;amp;= e^x&lt;br /&gt;
  \end{align}&lt;br /&gt;
\] &lt;br /&gt;
which is based on the above derivation. &lt;br /&gt;
Also note that \(M(e)\) at \(x = 0\) is 1. That is, the slope of the tangent line at \(x = 0\) is 1.&lt;/p&gt;
&lt;p&gt;How do we know that a number such as \(e\) exists?&lt;/p&gt;
&lt;p&gt;Without defining \(e\), we can show graphically that it must exist.&lt;/p&gt;
&lt;p&gt;Consider the graph of the function \(y = 2^x\), and compare the tangent line at \(x = 0\) (\(M(2)\)) to the secant line through the points \((0,1), (1,2)\):&lt;br /&gt;
&lt;img src="/images/svcalc/m2.png" alt="" /&gt;&lt;br /&gt;
Notice the slope of the line \(M(2)\) is less than the secant.&lt;/p&gt;
&lt;p&gt;Now compare the graph of the function \(y = 4^x\) and compare \(M(4)\) against the same secant:&lt;br /&gt;
&lt;img src="/images/svcalc/m4.png" alt="" /&gt;&lt;br /&gt;
Notice the slope of the line is greater than the secant.&lt;/p&gt;
&lt;p&gt;This shows that somewhere between the bases of 2 and 4, there is a number where \(M(a) = 1\).&lt;/p&gt;
&lt;p&gt;To fit this concept together with where we left the derivation off, we need to use the natural log.&lt;br /&gt;
If \(y = e^x\), then \(ln\;y = x\). That is, the natural log is the inverse of \(e^x\).&lt;/p&gt;
&lt;p&gt;A refresher on logarithms:&lt;br /&gt;
- \(ln(x_1x_2) = ln\;x_1 + ln\;x_2\)&lt;br /&gt;
- \(ln\;1 = 0\)&lt;br /&gt;
- \(ln\;e = 1\)&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/svcalc/ln.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Next, we need to cover computing the derivative of a logarithm. Remember from implicit differentiation, we can compute the derivative of a function if we know the derivative of it&amp;#8217;s inverse. That&amp;#8217;s the rational behind finding the derivative.&lt;/p&gt;
&lt;p&gt;First, lets define \(w = ln\;x\). Using the above rules of \(ln\) and \(e\) we can show that:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  e^w &amp;amp;= x \\&lt;br /&gt;
  \frac{\delta}{\delta x}e^w &amp;amp;= \frac{\delta}{\delta x} x \\&lt;br /&gt;
  &amp;amp;= 1 \\&lt;br /&gt;
  (\frac{\delta}{\delta w}e^w)(\frac{\delta w}{\delta x}) &amp;amp;= 1 \\&lt;br /&gt;
  e^w \frac{\delta w}{\delta x} &amp;amp;= 1 \\&lt;br /&gt;
  \frac{\delta w}{\delta x} &amp;amp;= \frac{1}{e^w} \\&lt;br /&gt;
  &amp;amp;= \frac{1}{x}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;See that \(\frac{\delta}{\delta w}e^w = e^w\) based on the assumption that \(M(e) = 1\).&lt;br /&gt;
&lt;a href="http://ocw.mit.edu/courses/mathematics/18-01-single-variable-calculus-fall-2006/lecture-notes/lec6.pdf"&gt;For further info, check the lecture notes for this lecture.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Therefore we get:&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\delta}{\delta x}ln\;x = \frac{1}{x}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;To summarize, we have these two rates of change:&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\delta}{\delta x} e^x = e^x&lt;br /&gt;
\]&lt;br /&gt;
and&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\delta}{\delta x} ln\;x = \frac{1}{x}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;With these two derivatives in hand, we can return to the task of solving \(M(a)\), and so differentiate \(a^x\). There are two methods we can use to solve any exponential.&lt;/p&gt;
&lt;p&gt;Method 1:&lt;/p&gt;
&lt;p&gt;Convert the exponential to base \(e\):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    a^x &amp;amp;= (e^{ln\;a})^x \\&lt;br /&gt;
    &amp;amp;= e^{x\;ln\;a}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
and then differentiate:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{\delta}{\delta x}a^x &amp;amp;= \frac{\delta}{\delta x}e^{x\;ln\;a} \\&lt;br /&gt;
  &amp;amp;= (ln\;a)e^{x\;ln\;a}&lt;br /&gt;
  &amp;amp;= (ln\;a)a^x&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
and we can see therefore that \(M(a) = ln\;a\).&lt;/p&gt;
&lt;p&gt;The above works because of 2 things, and can be illustrated as follows:&lt;br /&gt;
\[&lt;br /&gt;
  \frac{\delta}{\delta x}e^{3x} = 3e^{3x}&lt;br /&gt;
\]&lt;br /&gt;
The 3 is the derivative of \(3x\), and is multiplied by the derivative of \(e^{3x}\), which is \(e^{3x}\).&lt;br /&gt;
The same is occuring above. \(ln\;a\) is a constant, and so we differentiate out the \(x\) and multiply it by the derivative of \(e\), which is itself.&lt;/p&gt;
&lt;p&gt;Method 2:&lt;/p&gt;
&lt;p&gt;The second method involves logarithmic differentiation.&lt;/p&gt;
&lt;p&gt;Sometimes it&amp;#8217;s easier to differentiate the logarithm of a function instead of the function itself.&lt;br /&gt;
Lets assume some function \(u\), and solve:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta u} ln\;u &amp;amp;= \left(\frac{\delta ln\;u}{\delta u}\right)\left(\frac{\delta u}{\delta x}\right) \\&lt;br /&gt;
    &amp;amp;= \frac{1}{u} \frac{\delta u}{\delta x}&lt;br /&gt;
    &amp;amp;= \frac{u&amp;#8217;}{u}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
where we switch notation in the last step.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s easy to see where to go now from here to solve for \(a^x\):&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x} a^x \bigg| u = a^x \\&lt;br /&gt;
    ln\;u &amp;amp;= x\;ln\;a \\&lt;br /&gt;
    \frac{\delta}{\delta x} x\;ln\;a &amp;amp;= ln\;a \\&lt;br /&gt;
    (a^x)&amp;#8217; &amp;amp;= (ln\;a)a^x&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2 of method 2&lt;/b&gt;&lt;br /&gt;
An example of having moving exponents and a moving base.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s consider the function:&lt;br /&gt;
\[&lt;br /&gt;
  v = x^x&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Solve \(\frac{\delta}{\delta x} v\) using logarithmic differentiation:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    ln\;v &amp;amp;= x\;ln\;x \\&lt;br /&gt;
    (ln\;v)&amp;#8217; &amp;amp;= ln\;x(x)&amp;#8217; + x(ln\;x)&amp;#8217; \\&lt;br /&gt;
    &amp;amp;= ln\;x + x . \frac{1}{x} \\&lt;br /&gt;
    &amp;amp;= ln\;x + 1 \\&lt;br /&gt;
    \frac{v&amp;#8217;}{v} &amp;amp;= ln\;x + 1 \\&lt;br /&gt;
    v&amp;#8217; &amp;amp;= v(ln\;x + 1) \\&lt;br /&gt;
    &amp;amp;= x^x(1 + ln\;x)&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
Where on the second line, we apply the product rule.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 3&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re going to evaluate:&lt;br /&gt;
\[&lt;br /&gt;
  \lim_{n \to \infty}\left(1 + \frac{1}{n}\right)^n  &lt;br /&gt;
\]&lt;br /&gt;
\[&lt;br /&gt;
  ln \left( \left(1 + \frac{1}{n} \right)^n \right) = n\;ln\left(1 + \frac{1}{n}\right)&lt;br /&gt;
\]&lt;br /&gt;
here, we&amp;#8217;re going to assign \(\Delta x = \frac{1}{n}\), which makes \(n = \frac{1}{\Delta x}\):&lt;br /&gt;
\[&lt;br /&gt;
  n\;ln \left( 1 + \frac{1}{n} \right) = \frac{1}{\Delta x} (ln(1 + \Delta x) &amp;#8211; ln\;1)&lt;br /&gt;
\]&lt;br /&gt;
here, we&amp;#8217;re adding 0, in the form of \(ln\;1\).&lt;br /&gt;
This results in an equation that matches the form of another equation we know:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{ln(1 + \Delta x) &amp;#8211; ln\;1}{\Delta x} &amp;amp;= \frac{\delta}{\delta x}ln\;x \quad \text{at x = 1} \\&lt;br /&gt;
  &amp;amp;= \frac{1}{x} \quad \text{at x = 1} \\&lt;br /&gt;
  &amp;amp;= 1&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;br /&gt;
Now we can just work back:&lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \lim_{n \to \infty}\left( 1 + \frac{1}{n} \right)^n &amp;amp;= e^{\left[ ln \left[ lim_{n \to \infty} \left( 1 + \frac{1}{n} \right)^n \right] \right]} \\&lt;br /&gt;
  &amp;amp;= e^1 \\&lt;br /&gt;
  &amp;amp;= e&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=5mgRHqltB58:dM3Y4QgsEvM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=5mgRHqltB58:dM3Y4QgsEvM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=5mgRHqltB58:dM3Y4QgsEvM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=5mgRHqltB58:dM3Y4QgsEvM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=5mgRHqltB58:dM3Y4QgsEvM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=5mgRHqltB58:dM3Y4QgsEvM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=5mgRHqltB58:dM3Y4QgsEvM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/5mgRHqltB58" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-single-variable-calculus/week-3</feedburner:origLink></entry>
 
 <entry>
   <title>MIT OCW Linear Algebra - Week 2</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/zOSVyvnarOM/week-2" />
   <updated>2012-02-03T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-linear-algebra/week-2</id>
   <content type="html">&lt;h2&gt;Matrix Multiplication&lt;/h2&gt;
&lt;p&gt;Consider the problem of multiplying two matrices:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  A \times B = C&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We can view this problem in 4 different ways.&lt;/p&gt;
&lt;p&gt;The first way is as a row x columns problem.&lt;br /&gt;
Consider the element \(C_{i,j}\). It is given by:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  C_{i,j} &amp;amp;= A_{i,1} B_{1,j} + A_{i,2} B_{2,j} + \ldots \\&lt;br /&gt;
  &amp;amp;= \sum_{k=1}^n A_{i,k} B_{k,j}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This illustrates the matrix multiplication rule that:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  m \times n \;. n \times p = m \times p&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Namely, you can only multiply matrices if the first matrix has the same number of columns as the second does rows. The result of the multiplication is a matrix with the same amount of rows as the first matrix and the same amount of columns as the second matrix.&lt;/p&gt;
&lt;p&gt;We can also think of multiplying matrices in terms of multiplying columns, or vectors. In the case of \(AB = C\), we can think of \(B\) as a group of column vectors: \(A \times [\vec{b_1}, \vec{b_2}, \vec{b_3}] = [A \vec{b_1}, A \vec{b_2}, A \vec{b_3}] \). Each column of C is a combination of the columns of A.&lt;/p&gt;
&lt;p&gt;Another way we can think of multiplying matrices is in terms of multiplying rows. In the case of \(AB = C\), we can think of \(A\) as a group of row vectors: \( \begin{bmatrix} \vec{a_1} \\ \vec{a_2} \\ \vec{a_3} \end{bmatrix} \times B = \begin{bmatrix} \vec{a_1}B \\ \vec{a_2}B \\ \vec{a_3}B \end{bmatrix} \). That is, each row of C is a combination of the rows of B.&lt;/p&gt;
&lt;p&gt;Next, we can think of multiplying matrices in terms of columns x rows.&lt;br /&gt;
Remember a column is a m x 1 matrix, and a row is a 1 x n matrix. Multiplying these together gives:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  m \times 1 \;. 1 \times p = m \times p&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Consider \(AB = C \) generally:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    \vec{a_1} &amp;amp; \vec{a_2} &amp;amp; \vec{a_3}&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \times&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    \vec{b_1} \\&lt;br /&gt;
    \vec{b_2} \\&lt;br /&gt;
    \vec{b_3}&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \vec{a_1} \vec{b_1} + \vec{a_2} \vec{b_2} + \vec{a_3} \vec{b_3}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;where \(\vec{a}\) are column vectors of dimension \(m \times 1\) and \(\vec{b}\) are row vectors of dimension \(1 \times n\), and \(\vec{a}\vec{b}\) is a matrix of dimension \(m \times n\).&lt;/p&gt;
&lt;p&gt;Lastly, it should be noted that you can segment matrices and multiply the segments and still obtain the correct answer, so long as the segments are compatible.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    a_1 &amp;amp; a_2 \\&lt;br /&gt;
    a_3 &amp;amp; a_4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \times&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    b_1 &amp;amp; b_2 \\&lt;br /&gt;
    b_3 &amp;amp; b_4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    a_1 b_1 + a_2 b_3 &amp;amp; a_1 b_2 + a_2 b_4 \\&lt;br /&gt;
    a_3 b_1 + a_4 b_3 &amp;amp; a_3 b_2 + a_b b_4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;where \(a\) and \(b\) are matrices, segments of a larger matrix.&lt;/p&gt;
&lt;h2&gt;Inverses&lt;/h2&gt;
&lt;p&gt;Inverses don&amp;#8217;t always exist. Not every matrix is invertable. There are two kinds of inverses. Left inverse (\(A^{-1}A = I\)) and right inverse (\(AA^{-1} = I\)).&lt;/p&gt;
&lt;p&gt;For a square matrix, \(A^{-1}A = I = AA^{-1}\) is true, if A has an inverse.&lt;/p&gt;
&lt;p&gt;A matrix that has an inverse is called invertible or nonsingular.&lt;/p&gt;
&lt;h3&gt;Singular Matrices&lt;/h3&gt;
&lt;p&gt;The following matrix is singular, and thus has no inverse:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 2 \\&lt;br /&gt;
  3 &amp;amp; 6&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The above matrix is singular because it&amp;#8217;s determinate is 0. Determinates are covered later. It is also singular because each column is a multiple of the other, that is, they lie on the same line. When this matrix is multiplied with another matrix, the resultant matrix&amp;#8217;s columns will be a combination of the above matrix&amp;#8217;s columns &amp;#8211; and they too will lie on the same line. There is no way to achieve \(\begin{bmatrix}1 &amp;amp; 0 \\ 0 &amp;amp; 1 \end{bmatrix}\) because neither column of \(I\) lies on that line.&lt;/p&gt;
&lt;p&gt;Another reason a square matrix won&amp;#8217;t have an inverse is that it is possible to find a non-zero vector \(x\) such that \(Ax = 0\):&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 3 \\&lt;br /&gt;
  2 &amp;amp; 6&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  3 \\ -1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  = 0&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;A matrix can&amp;#8217;t have an inverse if some combination of it&amp;#8217;s columns gives nothing.&lt;br /&gt;
If we assume A does have an inverse, then:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  (Ax)A^{-1} &amp;amp;= 0A^{-1} \\&lt;br /&gt;
  x &amp;amp;=0&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;which we can see is clearly not true (\(x = \begin{bmatrix} 3 \\ -1 \end{bmatrix} \)), therefore this matrix does not have an inverse.&lt;/p&gt;
&lt;h3&gt;Non-singular matrices&lt;/h3&gt;
&lt;p&gt;Consider the following matrix:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 3 \\&lt;br /&gt;
  2 &amp;amp; 7&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This matrix is invertible and non-singular.&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 3 \\&lt;br /&gt;
  2 &amp;amp; 7&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  a &amp;amp; c \\&lt;br /&gt;
  b &amp;amp; d&lt;br /&gt;
  \end{bmatrix} = &lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 0 \\&lt;br /&gt;
  0 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We need to find out the value of \(A^{-1}\), \(\begin{bmatrix} a &amp;amp; c \\ b &amp;amp; d \end{bmatrix}\).&lt;br /&gt;
Going back to matrix multiplication, we can see that we can decompose this into two problems:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 3 \\&lt;br /&gt;
    2 &amp;amp; 7&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    a \\ b&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 \\ 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 3 \\&lt;br /&gt;
    2 &amp;amp; 7&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    c \\ d&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    0 \\ 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;These two equations can be solved at once using Gauss-Jordan. First, create an augmented matrix, with the left hand side as \(A\) and the right hand side as \(I\):&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \left[&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
    1 &amp;amp; 3 \\&lt;br /&gt;
    2 &amp;amp; 7&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \quad&lt;br /&gt;
  \left|&lt;br /&gt;
  \quad&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
    1 &amp;amp; 0 \\&lt;br /&gt;
    0 &amp;amp; 1&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \right.&lt;br /&gt;
  \right]&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We can now perform Gaussian elimination on this augmented matrix:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \left[&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
    1 &amp;amp; 3 \\&lt;br /&gt;
    0 &amp;amp; 1&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \quad&lt;br /&gt;
  \left|&lt;br /&gt;
  \quad&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
    1 &amp;amp; 0 \\&lt;br /&gt;
    -2 &amp;amp; 1&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \right.&lt;br /&gt;
  \right]&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The left hand side is now in upper triangular form, and under normal Gaussian substitution, we&amp;#8217;d finish. However in Gauss-Jordan, we then do a upwards elimination to achieve \(I\) on the left side:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \left[&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
    1 &amp;amp; 0 \\&lt;br /&gt;
    0 &amp;amp; 1&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \quad&lt;br /&gt;
  \left|&lt;br /&gt;
  \quad&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
    7 &amp;amp; -3 \\&lt;br /&gt;
    -2 &amp;amp; 1&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \right.&lt;br /&gt;
  \right]&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The right hand side is now \(A^{-1}\).&lt;/p&gt;
&lt;p&gt;We can show how Gauss-Jordan works by the following sum:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  E[A \quad I] &amp;amp;= [EA \quad EI] \\&lt;br /&gt;
  &amp;amp;= [I \quad E]&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;where E is the elimination matrix that performs the above calculation (augmented matrices). You can see that if \(E \times A = I\), then \(E\) must be \(A^{-1}\), and therefore \(E \times I = E\), which gives the result we observed above.&lt;br /&gt;
\(E \times A = I\) was true because we &lt;i&gt;made&lt;/i&gt; it true, by eliminating to \(I\).&lt;/p&gt;
&lt;h3&gt;Inverse of a product&lt;/h3&gt;
&lt;p&gt;We know \(AA^{-1} = I = A^{-1}A\).&lt;/p&gt;
&lt;p&gt;For products, \(AB B^{-1}A^{-1} = I\) This is due to the associative nature of matrix multiplication.&lt;br /&gt;
Performing the calculation:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  AB ( B^{-1}A^{-1} ) &amp;amp;= I \\&lt;br /&gt;
  A ( B B^{-1} ) A &amp;amp;= I \\&lt;br /&gt;
  AI A^{-1} &amp;amp;= I \\&lt;br /&gt;
  A A^{-1} &amp;amp;= I \\&lt;br /&gt;
  I &amp;amp;= I&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;The same holds for \(B^{-1}A^{-1}AB = I\), which is placing the inverse group on the left of the equation.&lt;/p&gt;
&lt;p&gt;A note about transposing. Two things about transposing a matrix:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;When you transpose a matrix, you have to swap arguments:&lt;br /&gt;
  \[&lt;br /&gt;
    A A^{-1} = I = (A^{-1})^T A^T&lt;br /&gt;
  \]&lt;/li&gt;
	&lt;li&gt;The inverse of a transposed matrix is the inverse of the matrix transposed:&lt;br /&gt;
  \[&lt;br /&gt;
    (A^{-1})^T = (A^T)^{-1}&lt;br /&gt;
  \]&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Factorization into A = LU&lt;/h2&gt;
&lt;p&gt;Elimination with no row matrices&lt;/p&gt;
&lt;p&gt;Consider the following:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  E_{2,1}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    2 &amp;amp; 1 \\&lt;br /&gt;
    8 &amp;amp; 7&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  2 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This is the first step in Gaussian elimination, where the first matrix is matrix \(A\), and the last matrix is matrix \(U\). The \(E_{2,1}\) matrix elminates \(A_{2,1}\) to make \(U\) an upper-triangular matrix.&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 0 \\&lt;br /&gt;
    -4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    2 &amp;amp; 1 \\&lt;br /&gt;
    8 &amp;amp; 7&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  2 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;is the solution for \(E_{2,1}\).&lt;/p&gt;
&lt;p&gt;To put this in the form of \(A = LU\), we need to recognise that \(L = E_{2,1}^{-1}\), and multiply both sides:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{array}{rcl}&lt;br /&gt;
  ( E_{2,1} E_{2,1}^{-1} )&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    2 &amp;amp; 1 \\&lt;br /&gt;
    8 &amp;amp; 7&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&amp;amp;&lt;br /&gt;
  E_{2,1}^{-1}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  2 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \\&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    2 &amp;amp; 1 \\&lt;br /&gt;
    8 &amp;amp; 7&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&amp;amp;&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 0 \\&lt;br /&gt;
    4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  2 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \end{array}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Notice that \(U\) is an upper-triangle and \(L\) is a lower-triangle. \(U\) has the pivots in the matrix, and these can be pulled out:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    2 &amp;amp; 1 \\&lt;br /&gt;
    0 &amp;amp; 3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    2 &amp;amp; 0 \\&lt;br /&gt;
    0 &amp;amp; 3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; \frac{1}{2} \\&lt;br /&gt;
    0 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;where the first matrix on the right hand side is the matrix \(P\) for pivot, and is a diagonal matrix, and the second matrix is \(U\), the upper triangular matrix.&lt;/p&gt;
&lt;p&gt;Now lets consider the same operations a larger matrix, assuming again we don&amp;#8217;t perform a row exchange:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  E_{3,2}E_{3,1}E_{2,1}A = U&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Where we eliminate \(A_{2,1}\) first, then from the resultant matrix we elminate \(A_{3,1}\) and then from that matrix we eliminate \(A_{3,2}\). To put this into the form of \(A = LU\), we need to invert the matrices and move them to the other side of the equation:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  A &amp;amp;= E_{2,1}^{-1}E_{3,1}^{-1}E_{3,2}^{-1}U \\&lt;br /&gt;
  &amp;amp;= LU&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We perform \(E_{2,1}^{-1}E_{3,1}^{-1}E_{3,2}^{-1}\) instead of \((E_{3,2}E_{3,1}E_{2,1})^{-1}\) because it&amp;#8217;s easier to compute.&lt;/p&gt;
&lt;p&gt;If we perform no row exchanges, the multipliers in \(E\) used to eliminate elements of A go directly into \(L\). For example:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{array}{rl}&lt;br /&gt;
  E_{2,1}^{-1}E_{3,1}^{-1}E_{3,2}^{-1}U =&amp;amp;&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 0 &amp;amp; 0 \\ &lt;br /&gt;
    0 &amp;amp; 1 &amp;amp; 0 \\ &lt;br /&gt;
    0 &amp;amp; 5 &amp;amp; 1 &lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  I&lt;br /&gt;
  \begin{bmatrix} &lt;br /&gt;
    1 &amp;amp; 0 &amp;amp; 0 \\ &lt;br /&gt;
    2 &amp;amp; 1 &amp;amp; 0 \\ &lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 1 &lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  U \\&lt;br /&gt;
  =&amp;amp;&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 0 &amp;amp; 0 \\ &lt;br /&gt;
    0 &amp;amp; 1 &amp;amp; 0 \\ &lt;br /&gt;
    0 &amp;amp; 5 &amp;amp; 1 &lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix} &lt;br /&gt;
    1 &amp;amp; 0 &amp;amp; 0 \\ &lt;br /&gt;
    2 &amp;amp; 1 &amp;amp; 0 \\ &lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 1 &lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  U \\&lt;br /&gt;
  =&amp;amp;&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
    2 &amp;amp; 1 &amp;amp; 1 \\&lt;br /&gt;
    0 &amp;amp; 5 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  U \\&lt;br /&gt;
  =&amp;amp;&lt;br /&gt;
  LU&lt;br /&gt;
  \end{array}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;In terms of computation, performing elimination on an \(n \times n\) matrix is \(O(\frac{1}{3}n^3)\) in the worst case. It&amp;#8217;s no coincidence that this looks like the integral of \(x^2\), as it represents a small change in \(x^2\) over time.&lt;/p&gt;
&lt;p&gt;There are 6 permutation matricies for \(3 \times 3\) matricies:&lt;br /&gt;
&lt;img src="/images/la/3x3perms.png" alt="" /&gt;&lt;br /&gt;
For permutations matrices, \(P^{-1} = P^T\). In general, there are \(n!\) for an \(n \times n\) matrix.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=zOSVyvnarOM:N-10_L99Rt4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=zOSVyvnarOM:N-10_L99Rt4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=zOSVyvnarOM:N-10_L99Rt4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=zOSVyvnarOM:N-10_L99Rt4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=zOSVyvnarOM:N-10_L99Rt4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=zOSVyvnarOM:N-10_L99Rt4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=zOSVyvnarOM:N-10_L99Rt4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/zOSVyvnarOM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-linear-algebra/week-2</feedburner:origLink></entry>
 
 <entry>
   <title>MIT OCW Single Variable Calculus - Week 2</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/sEv5NB6of8U/week-2" />
   <updated>2012-01-25T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-single-variable-calculus/week-2</id>
   <content type="html">&lt;h2&gt;Week 2&lt;/h2&gt;
&lt;h3&gt;Derivative Formulas&lt;/h3&gt;
&lt;p&gt;To work towards the goal of &amp;#8220;differentiating everything&amp;#8221;, need to talk about derivative formulas.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Specfic &amp;#8211; \(f&amp;#8217;(x)\), where \(f(x) = x^n, \frac{1}{x}\) as a few examples.&lt;/li&gt;
	&lt;li&gt;General &amp;#8211; \((u + v)&amp;#8217; = u&amp;#8217; + v&amp;#8217;\) and \((cu)&amp;#8217; = cu&amp;#8217;\) where c is constant, as a few examples.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Start with specific trigonometric derivative formulas.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;\(\frac{\delta}{\delta x} sin \; x\)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \frac{\delta}{\delta x} sin \; x = \lim_{x \to 0} \frac{sin(x + \Delta) \; &amp;#8211; sin(x)}{\Delta x}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;To solve this, we need to revist the trigonometric sum and difference formulas, namely:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  sin(A + B) = sin A \; cos B + cos A \; sin B&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://oakroadsystems.com/twt/sumdiff.htm"&gt;This is a proof of the identity, using Eulers formula&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Going back to the derivative:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{\delta}{\delta x} sin \; x &amp;amp;= \lim_{x \to 0} \frac{sin(x + \Delta) \; &amp;#8211; sin(x)}{\Delta x} \\&lt;br /&gt;
  &amp;amp;= \lim_{x \to 0} \frac{sin\:x \; cos\:\Delta x + cos\;x \; sin\:\Delta x &amp;#8211; sin\:x}{\Delta x} \\&lt;br /&gt;
  &amp;amp;= \lim_{x \to 0} \quad sin\:x(\frac{cos\:\Delta x &amp;#8211; 1}{\Delta x}) + cos\:x(\frac{sin\:\Delta x}{\Delta x}) \\&lt;br /&gt;
  &amp;amp;= cos\:x&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;due to the fact that \(\frac{cos\:\Delta x &amp;#8211; 1}{\Delta x}\) tends to 0 as \(\Delta x\) tends to 0, and \(\frac{sin\:\Delta x}{\Delta x}\) tends to 1 as \(\Delta x\) tends to 0. Label these as A and B respectively, as we will prove them later.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;\(\frac{\delta}{\delta x} cos x\)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Same as above, only this time using the identity:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  cos(A + B) = cos A \; cos B &amp;#8211; sin A \; sin B&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x} cos \; x &amp;amp;= \lim_{x \to 0} \frac{cos(x + \Delta) \; &amp;#8211; cos(x)}{\Delta x} \\&lt;br /&gt;
    &amp;amp;= \lim_{x \to 0} \frac{cos\;x \: cos\;\Delta x &amp;#8211; sin\;x \: sin\;\Delta x &amp;#8211; cos\;x}{\Delta x} \\&lt;br /&gt;
    &amp;amp;= \lim_{x \to 0} \quad cos\;x(\frac{cos\;\Delta x &amp;#8211; 1}{\Delta x}) &amp;#8211; sin\;x(\frac{\sin\;\Delta x}{\Delta x}) \\&lt;br /&gt;
    &amp;amp;= \quad &amp;#8211; sin\;x&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;again, by A and B as stated above.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Proofs of A and B&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;First, some remarks:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \frac{\delta}{\delta x} cos\;x \quad \Bigg|^{x=0}&lt;br /&gt;
  \quad \lim_{\Delta x \to 0} \frac{cos(\Delta x) &amp;#8211; 1}{\Delta x} &lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This shows that the rate of change of \(cos x\) at \(x = 0\) is a limit as \(\Delta x\) tends to 0, which has been simplified:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    &amp;amp;\frac{cos(0 + \Delta x) &amp;#8211; cos(0)}{\Delta x} \\&lt;br /&gt;
    = &amp;amp;\frac{cos(\Delta x) &amp;#8211; 1}{\Delta x}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;and likewise&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \frac{\delta}{\delta x} sin\;x \quad \Bigg|^{x=0}&lt;br /&gt;
  \quad \lim_{\Delta x \to 0} \frac{sin(\Delta x)}{\Delta x} &lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;because of the simplification:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    &amp;amp;\frac{sin(0 + \Delta x) &amp;#8211; sin(0)}{\Delta x} \\&lt;br /&gt;
    = &amp;amp;\frac{sin(\Delta x)}{\Delta x}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We should note that the derivatives of sine and cosine at \(x = 0\) give all values of \(\frac{\delta}{\delta x} sin x\), \(\frac{\delta}{\delta x} cos x\)&lt;/p&gt;
&lt;p&gt;Back to the proofs:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Property B&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Geometric proof:&lt;/p&gt;
&lt;p&gt;Lets rename \(\Delta x\) as \(\theta\).&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/svcalc/b-proof.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Consider the ratio of the arc length to the line \(sin \theta\). Then double it for the two \(\theta\) that were drawn:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  &amp;amp;\frac{2 sin \theta}{2 \theta} \\&lt;br /&gt;
  = &amp;amp;\frac{sin \theta}{\theta}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Now, as \(\theta\) approaches 0, the lines \(sin \theta\) and \(arclength \theta\) get close and close to the same line, so the result of the ratio is 1, intuitively because short pieces of curves are nearly straight.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Property A&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The basis for the proof for cosine is the same as the proof for sine &amp;#8211; that of short pieces of curves being nearly straight.&lt;/p&gt;
&lt;p&gt;First, \(cos \theta\) is going to be negative, so we need to invert the statement:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \frac{1 &amp;#8211; cos \theta}{\theta}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/svcalc/a-proof.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;This is a similar image as before, only magnified.&lt;br /&gt;
The distance from the centre of the circle to the circumference is 1 (because this is a unit circle, and the gap between the \(sin \theta\) line and the circumference is \(1 &amp;#8211; cos \theta\). As \(\theta\) tends to 0, this gap gets smaller and smaller, and as such, \(\frac{1 &amp;#8211; cos \theta}{\theta}\) tends to 0.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt; TO &lt;span class="caps"&gt;SELF&lt;/span&gt; &amp;#8211; &lt;span class="caps"&gt;RECORD&lt;/span&gt; &lt;span class="caps"&gt;GEOMETRIC&lt;/span&gt; &lt;span class="caps"&gt;PROOF&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;General Derivative Rules&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Product Rule&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  (uv)&amp;#8217; = u&amp;#8217;v + uv&amp;#8217;&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;can be remembered as changing one variable at a time. Will be proven as such.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \frac{\delta}{\delta x} (x^n sin\;x) = nx^{n-1}sin\;x + x^n cos\;x&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Proof:&lt;/p&gt;
&lt;p&gt;Going back to first principles of calculus, we can rewrite the sum in terms of the rate of change:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  \frac{\delta}{\delta x} uv &amp;amp;= \lim_{\Delta x \to 0} \frac{u(x + \Delta x)v(x + \Delta x) &amp;#8211; u(x)v(x)}{\Delta x} \\&lt;br /&gt;
  &amp;amp;= \lim_{\Delta x \to 0} \frac{u(x + \Delta x)(v(x + \Delta x) &amp;#8211; v(x)) + v(x)(u(x + \Delta x) &amp;#8211; u(x))}{\Delta x} \qquad \text{(1)} \\ &lt;br /&gt;
  &amp;amp;= \lim_{\Delta x \to 0} u(x + \Delta x)\frac{\delta v}{\delta x} + v(x)\frac{\delta u}{\delta x} \\ &lt;br /&gt;
  &amp;amp;= uv&amp;#8217; + vu&amp;#8217;&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We converted the sum in (1) to a new form to aid in the proof. You can multiply out (1) to show that it is indeed equal:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  u(x + \Delta x)(v(x + \Delta x) &amp;#8211; v(x)) + v(x)(u(x + \Delta x) &amp;#8211; u(x)) &amp;amp;= u(x + \Delta x)v(x + \Delta x) &amp;#8211; v(x)u(x + \Delta x) + v(x)u(x + \Delta x) &amp;#8211; v(x)u(x) \\&lt;br /&gt;
  &amp;amp;= u(x + \Delta x)v(x + \Delta x) &amp;#8211; v(x)u(x)&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;As \(\Delta x\) tends to 0, then \(u(x + \Delta x)\) approaches \(u(x)\), which will complete the proof.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Quotient Rule&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \left(\frac{u}{v}\right)&amp;#8217; = \frac{u&amp;#8217;v &amp;#8211; uv&amp;#8217;}{v^2}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;only works when \(v \ne 0\).&lt;/p&gt;
&lt;p&gt;Proof:&lt;/p&gt;
&lt;p&gt;First, recall that \(\frac{\delta}{\delta x}\) is equal to \(\frac{\Delta y}{\Delta x}\) and we can compute \(\Delta y\) in a separate step, and then just divide by \(\Delta x\).&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \Delta \left( \frac{u}{v} \right) &amp;amp;= \frac{u + \Delta u}{v + \Delta v} &amp;#8211; \frac{u}{v} \\&lt;br /&gt;
    &amp;amp;= \frac{uv + v(\Delta u) &amp;#8211; uv &amp;#8211; u(\Delta v)}{(v + \Delta v)v} \\&lt;br /&gt;
    &amp;amp;= \frac{v(\Delta u) &amp;#8211; u(\Delta v)}{(v + \Delta v)v} \\&lt;br /&gt;
    \frac{\Delta \left( \frac{u}{v} \right) }{\Delta x} &amp;amp;= \frac{ \frac{\Delta u}{\Delta x}v &amp;#8211; u\frac{\Delta v}{\Delta x} }{(v + \Delta v)v} \\&lt;br /&gt;
    \frac{\delta}{\delta x} \left( \frac{u}{v} \right) &amp;amp;= \lim_{\Delta x \to 0} \frac{ \frac{\delta u}{\delta x}v &amp;#8211; u\frac{\delta v}{\delta x} }{v^2} \\&lt;br /&gt;
    &amp;amp;= \frac{u&amp;#8217;v &amp;#8211; uv&amp;#8217;}{v^2}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Let us reconsider the above, setting \(u = 1\):&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x} \left( \frac{1}{v} \right) &amp;amp;= \frac{-1v&amp;#8217;}{v^2} \\&lt;br /&gt;
    &amp;amp;= -v^{-2}v&amp;#8217;&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;and now, lets consider the above example generally, with \(\frac{1}{x^n}\) represented as \(x^{-n}\):&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta x} x^{-n} &amp;amp;= \frac{\delta}{\delta x} \left( \frac{1}{x^n} \right) \\&lt;br /&gt;
    &amp;amp;= -x^{-2n}nx^{n-1} \\&lt;br /&gt;
    &amp;amp;= -nx^{-n-1}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;You&amp;#8217;ll notice that this follows the same pattern that applies to \(x^n\).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Chain rule&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ll start by derriving the rule, then writing it down.&lt;/p&gt;
&lt;p&gt;Proof:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\Delta y}{\Delta t} &amp;amp;= \frac{\Delta y}{\Delta x} \frac{\Delta x}{\Delta t} \\&lt;br /&gt;
    \frac{\delta y}{\delta t} &amp;amp;= \frac{\delta y}{\delta x} \frac{\delta x}{\delta t}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TODO&lt;/span&gt;: &lt;span class="caps"&gt;FIND&lt;/span&gt; A &lt;span class="caps"&gt;BETTER&lt;/span&gt; &lt;span class="caps"&gt;PROOF&lt;/span&gt; OF &lt;span class="caps"&gt;THIS&lt;/span&gt;, OR &lt;span class="caps"&gt;SHOW&lt;/span&gt; A &lt;span class="caps"&gt;MORE&lt;/span&gt; &lt;span class="caps"&gt;EXPLICIT&lt;/span&gt; &lt;span class="caps"&gt;EXAMPLE&lt;/span&gt; *&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta t} (sin\;t)^{10} &amp;amp;= x^{10} &amp;amp; \text{Substituting x = sin t} \\&lt;br /&gt;
    &amp;amp;= 10x^9 cos\;t \\&lt;br /&gt;
    &amp;amp;= 10(sin\;t)^9 cos\;t &amp;amp; \text{Substituting the value of x back in}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Example 2:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    \frac{\delta}{\delta t} sin(10t) &amp;amp;= sin(x) &amp;amp; \text{Substituting x = 10t} \\&lt;br /&gt;
    &amp;amp;= cos(x) \times 10 \\&lt;br /&gt;
    &amp;amp;= cos(10t) \times 10 &amp;amp; \text{Substituting 10t = x back in}&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Higher derrivatives *&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Refers to multiple steps of differentiation.&lt;/p&gt;
&lt;p&gt;Consider the function \(u = u(x)\), then \(u&amp;#8217;\) is a new function in and of itself. We can differentiate this function: \(u&amp;#8217;&amp;#8217;\). This is the second derivative, and it too is a new function, and can be differentiated.&lt;/p&gt;
&lt;p&gt;You can continue this to any number of higher derrivatives, second, third, fourth, etc.&lt;/p&gt;
&lt;p&gt;Notation: &lt;br /&gt;
\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
  u&amp;#8217; &amp;amp;= \frac{\delta u}{\delta x} = \frac{\delta}{\delta x} u \\&lt;br /&gt;
  u&amp;#8217;&amp;#8217; &amp;amp;= \frac{\delta}{\delta x}\frac{\delta u}{\delta x} = \frac{\delta}{\delta x}\frac{\delta}{\delta x} u \\&lt;br /&gt;
  &amp;amp;= \left(\frac{\delta}{\delta x}\right)^2 u \\&lt;br /&gt;
  &amp;amp;= \frac{\delta^2}{(\delta x)^2} u \\&lt;br /&gt;
  &amp;amp;= \frac{\delta^2}{\delta x^2} u&lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{align}&lt;br /&gt;
    D^nx^n &amp;amp;= ? \\&lt;br /&gt;
    Dx^n &amp;amp;= nx^{n-1} \\&lt;br /&gt;
    D^2x^n &amp;amp;= n(n-1)x^{n-2} \\&lt;br /&gt;
    D^3x^n &amp;amp;= n(n-1)(n-2)x^{n-3} \\&lt;br /&gt;
    D^{n-1}x^n &amp;amp;= (n(n-1)(n-2) \ldots 2)x^1 \\&lt;br /&gt;
    D^nx^n &amp;amp;= (n(n-1)(n-2) \ldots 2 \times 1) \times 1 \\&lt;br /&gt;
    &amp;amp;= n! &lt;br /&gt;
  \end{align}&lt;br /&gt;
\]&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=sEv5NB6of8U:TQrdMUAO1uo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=sEv5NB6of8U:TQrdMUAO1uo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=sEv5NB6of8U:TQrdMUAO1uo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=sEv5NB6of8U:TQrdMUAO1uo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=sEv5NB6of8U:TQrdMUAO1uo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=sEv5NB6of8U:TQrdMUAO1uo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=sEv5NB6of8U:TQrdMUAO1uo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/sEv5NB6of8U" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-single-variable-calculus/week-2</feedburner:origLink></entry>
 
 <entry>
   <title>MIT OCW Single Variable Calculus - Week 1</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/PyPLIESnG1M/week-1" />
   <updated>2012-01-18T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-single-variable-calculus/week-1</id>
   <content type="html">&lt;h3&gt;Differentiation&lt;/h3&gt;
&lt;h4&gt;What is a derivative?&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Geometric interpretation&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Consider the problem of finding the tangent line to some function \(y=f(x)\) at \(P=(x_0,y_0)\):&lt;br /&gt;
&lt;img src="/images/svcalc/tangent.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The tangent line has an equation of the form \(y &amp;#8211; y_0 = m(x &amp;#8211; x_0)\), where m is the slope or gradient of the line.&lt;br /&gt;
Finding \(y_0\) is easy &amp;#8211; \(y_0 = f(x_0)\).&lt;br /&gt;
Finding m involves calculus &amp;#8211; \(m = f&amp;#8217;(x_0)\). &lt;br /&gt;
That is, \(f&amp;#8217;(x_0)\), the derivative of \(f\) at \(x_0\) is the slope of the tangent line to \(y = f(x)\) at P.&lt;/p&gt;
&lt;p&gt;Consider the following graph:&lt;br /&gt;
&lt;img src="/images/svcalc/secant.gif" alt="" /&gt;&lt;br /&gt;
How do we know which of these two lines is the tangent, given that both pass through the same point?&lt;br /&gt;
Lets define the point where the secant and the tangent intersect as P, and the other point on the secant as Q.&lt;br /&gt;
As the point Q gets closer to the point P, the slope of the secant line starts to match the slope of the tangent line.&lt;br /&gt;
Therefore:&lt;br /&gt;
The tangent is the limit of the secant line \(PQ\) as the point \(Q \rightarrow P\), assuming P is fixed.&lt;/p&gt;
&lt;p&gt;Again consider the secant line \(PQ\).&lt;br /&gt;
Calculating the gradient of \(PQ\):&lt;br /&gt;
The difference between Q&amp;#8217;s x value and P&amp;#8217;s x value is known as \(\Delta x\) (delta x), or the change in x.&lt;br /&gt;
The change in y is called \(\Delta f\) (in this case?).&lt;br /&gt;
The gradient between \(P\) and \(Q\) is the ratio of \(\frac{\Delta f}{\Delta x}\).&lt;br /&gt;
As the point Q gets closer to P, \(\Delta x\) gets smaller.&lt;br /&gt;
Thus \(m = \lim_{\Delta x \to 0} \frac{\Delta f}{\Delta x}\)&lt;/p&gt;
&lt;p&gt;If P is the point \((x_0, f(x_0))\), then we can represent Q as \((x_0 + \Delta x, f(x_0 + \Delta x))\).&lt;br /&gt;
&lt;b&gt;Therefore \(m = \lim_{\Delta x \to 0} \frac{f(x_0 + \Delta x) &amp;#8211; f(x_0)}{\Delta x}\).&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;This is the heart of the derivative.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Example:&lt;br /&gt;
Consider the graph for \(\frac{1}{x}\)&lt;br /&gt;
&lt;img src="/images/svcalc/1dividedbyx.png" alt="" /&gt;&lt;br /&gt;
Find the tanget at point \(x_0\):&lt;br /&gt;
$$m = \lim_{\Delta x \to 0} \frac{ \frac{1}{x_0 + \Delta x} &amp;#8211; \frac{1}{x_0} }{\Delta x}$$&lt;br /&gt;
$$m = \lim_{\Delta x \to 0} \frac{1}{\Delta x}\left( \frac{ x_0 &amp;#8211; (x_0 + \Delta x) }{ (x_0 + \Delta x)x_0 } \right)$$&lt;br /&gt;
$$m = \lim_{\Delta x \to 0} \frac{1}{\Delta x}\left( \frac{ -\Delta x }{ (x_0 + \Delta x)x_0 } \right)$$&lt;br /&gt;
$$m = \lim_{\Delta x \to 0} -\frac{1}{ (x_0 + \Delta x)x_0 }$$&lt;br /&gt;
$$m \rightarrow -\frac{1}{ x_0^2 }$$&lt;/p&gt;
&lt;p&gt;Example 2:&lt;br /&gt;
Find the area of the triangle formed by the axes and the curve described by \(y = \frac{1}{x}\).&lt;br /&gt;
This is a word problem with only one part of calculus &amp;#8211; the rest is regular math.&lt;br /&gt;
Graph the problem:&lt;br /&gt;
&lt;img src="/images/svcalc/triangle-area.png" alt="" /&gt;&lt;br /&gt;
The only part of the problem that involves calculus is finding the tangent. We found the gradient \(m\) above, so lets use that.&lt;br /&gt;
\(y &amp;#8211; y_0 = -\frac{1}{x_0^2}(x &amp;#8211; x_0)\)&lt;br /&gt;
To calculate the area of the triangle, we need the base length (along the \(x\) axis) and the base height (along the \(y\) axis).&lt;br /&gt;
We can find those by calculating the \(x\) intercept and \(y\) intercepts.&lt;br /&gt;
\(x\) intercept is at \(y = 0\), and we can express \(y_0\) in terms of \(f(x)\):&lt;br /&gt;
$$ &amp;#8211; \frac{1}{x_0} = -\frac{1}{x_0^2}(x &amp;#8211; x_0) $$&lt;br /&gt;
$$ &amp;#8211; \frac{1}{x_0} = -\frac{x}{x_0^2} + \frac{1}{x_0} $$&lt;br /&gt;
$$ \implies \frac{x}{x_0^2} = \frac{2}{x_0} $$ &lt;br /&gt;
$$ \implies x = 2x_0 $$&lt;br /&gt;
Using symmetry, we can find the \(y\) intercept quickly.&lt;br /&gt;
Firsly, a note about symmetry:&lt;br /&gt;
$$ y = \frac{1}{x} \implies xy = 1 \implies x = \frac{1}{y} $$&lt;br /&gt;
$$ \therefore y = 2y_0 $$&lt;br /&gt;
The area of a triangle is \(\frac{1}{2}\) base x perpendicular height.&lt;br /&gt;
\(\therefore area = \frac{1}{2}(2_x0)(2y_0) = 2x_0y_0\) = 2&lt;br /&gt;
The area is 2 because \(y = \frac{1}{x}\), and \(xy\) will always equal 1.&lt;/p&gt;
&lt;p&gt;Notation:&lt;br /&gt;
\(y = f(x), \Delta y = \Delta f\)&lt;br /&gt;
\(f&amp;#8217; = \frac{\delta f}{\delta x} = \frac{\delta y}{\delta x} = \frac{\delta}{\delta x}f = \frac{\delta}{\delta x}y\)&lt;/p&gt;
&lt;p&gt;Example 3:&lt;br /&gt;
\(y = \frac{\delta}{\delta x}x^n\)&lt;br /&gt;
$$ \frac{\Delta f}{\Delta x} = \lim_{\Delta x \to 0} \frac{(x + \Delta x)^n &amp;#8211; x^n}{\Delta x} $$&lt;br /&gt;
In order to solve this, we need to revist the binomial theorem (algebra).&lt;br /&gt;
Binomial theorem states that:&lt;br /&gt;
\( (x + \Delta x)^n = (x + \Delta x) &amp;#8230; (x + \Delta x) \)&lt;br /&gt;
\( = x^n + nx^{n-1} + O((\Delta x)^n)\)&lt;br /&gt;
continuing:&lt;br /&gt;
$$ \frac{\Delta f}{\Delta x} = \frac{1}{\Delta x}\big((x + \Delta x)^n &amp;#8211; x^n \big) $$&lt;br /&gt;
$$ \frac{\Delta f}{\Delta x} = \frac{1}{\Delta x}\big(x^n + nx^{n-1}\Delta x + O((\Delta x)^n) &amp;#8211; x^n \big) $$&lt;br /&gt;
$$ \frac{\Delta f}{\Delta x} = \frac{1}{\Delta x}\big(nx^{n-1}\Delta x + O((\Delta x)^n) \big) $$&lt;br /&gt;
$$ \frac{\Delta f}{\Delta x} = nx^{n-1} + O((\Delta x)^n) $$&lt;br /&gt;
$$ \frac{\Delta f}{\Delta x} = \lim_{\Delta x \to 0} nx^{n-1} + O((\Delta x)^n) = nx^{n-1} $$&lt;br /&gt;
$$ \therefore \frac{\delta}{\delta x}x^n = nx^{n-1} $$&lt;/p&gt;
&lt;h3&gt;Rate of Change&lt;/h3&gt;
&lt;p&gt;Geometrically, a derivative can be thought of as the slope of a tangent line for a curve.&lt;br /&gt;
It can also be considered from the point of view of relative rate of change. That is, the change in variables \(x\) and \(y\) for a given function \(f(x)\).&lt;br /&gt;
\(\frac{\Delta x}{\Delta y}\) is the &lt;b&gt;average&lt;/b&gt; rate of change &amp;#8211; that is, the entire change over the entire interval.&lt;br /&gt;
\(\frac{\delta x}{\delta y}\) is the average rate of change limited, and is the &lt;b&gt;instantaneous&lt;/b&gt; rate of change.&lt;/p&gt;
&lt;p&gt;Examples:&lt;br /&gt;
1. q = charge, \(\frac{\delta q}{\delta t}\) = current. The rate of change in charge over time is current.&lt;br /&gt;
2. s = distance, \(\frac{\delta s}{\delta t}\) = speed. The rate of change in distance over time is speed.&lt;/p&gt;
&lt;p&gt;Consider the &lt;span class="caps"&gt;MIT&lt;/span&gt; pumpkin drop:&lt;br /&gt;
From the top of one of the buildings in &lt;span class="caps"&gt;MIT&lt;/span&gt;, on Halloween, students drop pumpkins from the top of building to the ground.&lt;br /&gt;
Assume the building is 80m high, and assume the rate of acceleration due to gravity is 5m&lt;sup&gt;2&lt;/sup&gt; (not 9.8m&lt;sup&gt;2&lt;/sup&gt;).&lt;br /&gt;
\( h = 80 &amp;#8211; 5t^2 \)&lt;br /&gt;
at t = 0, h = 80&lt;br /&gt;
at t = 4, h = 0&lt;/p&gt;
&lt;p&gt;The &lt;b&gt;average&lt;/b&gt; speed is:&lt;br /&gt;
\(\frac{\Delta h}{\Delta t} = \frac{0 &amp;#8211; 80}{4 &amp;#8211; 0} = -20m/s \)&lt;/p&gt;
&lt;p&gt;The &lt;b&gt;instantaneous&lt;/b&gt; speed as it hits the ground is: &lt;br /&gt;
\(\frac{\delta}{\delta t}h = 0 &amp;#8211; 10t\) (differentiated the function for height)&lt;br /&gt;
at t = 4, &lt;b&gt;instantaneous&lt;/b&gt; speed is -40m/s.&lt;/p&gt;
&lt;p&gt;Examples that don&amp;#8217;t involve time:&lt;br /&gt;
3. T = temperature, \(\frac{\delta T}{\delta x}\) = temperature gradient (used in weather forecasting &amp;amp; airflow)&lt;br /&gt;
4. Sensitivity of measurements&lt;/p&gt;
&lt;h2&gt;Limits &amp;amp; Continuity&lt;/h2&gt;
&lt;p&gt;Left &amp;amp; right hand limits.&lt;br /&gt;
\(\lim_{x \to x_0^+}\) &amp;#8211; right hand limit. Says that x is bigger than \(x_0\) and we&amp;#8217;re approaching \(x_0\) with a negative \(\Delta\)&lt;br /&gt;
\(\lim_{x \to x_0^-}\) &amp;#8211; left hand limit. Says that x is smaller than \(x_0\) and we&amp;#8217;re approaching \(x_0\) with a positive \(\Delta\)&lt;/p&gt;
&lt;p&gt;Example:&lt;br /&gt;
$$&lt;br /&gt;
  f(x) = \left\{ &lt;br /&gt;
    \begin{array}{l l}&lt;br /&gt;
      x + 1 &amp;amp; \quad x &amp;gt; 0\\&lt;br /&gt;
      -x + 2 &amp;amp; \quad x &amp;lt; 0\\&lt;br /&gt;
    \end{array} \right.&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;$$\lim_{x \to x_0^+} f(x) = \lim_{x \to x_0} x + 1 = 1$$&lt;/p&gt;
&lt;p&gt;$$\lim_{x \to x_0^-} f(x) = \lim_{x \to x_0^-} -x + 2 = 2$$&lt;/p&gt;
&lt;p&gt;Note: we didn&amp;#8217;t need x = 0 value.&lt;/p&gt;
&lt;p&gt;Continuity:&lt;br /&gt;
\(f(x)\) is continuous at \(x_0\) when \(\lim_{x \to x_0} = f(x_0\)&lt;br /&gt;
Requirements:&lt;br /&gt;
- \(\lim_{x \to x_0} f(x)\) exists (from left &amp;amp; right, and left &amp;amp; right must be the same)&lt;br /&gt;
- \(f(x_0)\) is defined&lt;br /&gt;
- Both of the above are equal to each other&lt;/p&gt;
&lt;p&gt;Continuous functions are easier to calculate limits for because you can just insert the \(x_0\) term into the function and determine the limit.&lt;/p&gt;
&lt;p&gt;Discontinuity:&lt;br /&gt;
If \(f(x)\) is not continuous, then it is discontinuous.&lt;br /&gt;
&lt;b&gt;Jump discontinuity&lt;/b&gt; &amp;#8211; Limit from left and right exist but are not equal&lt;br /&gt;
&lt;b&gt;Removable discontinuity&lt;/b&gt; &amp;#8211; Limit from left and right are equal. Discontinuity can be removed by redefining the function for the point of discontinuity.&lt;br /&gt;
Example:&lt;br /&gt;
$$&lt;br /&gt;
  \begin{array}{1 1}&lt;br /&gt;
  g(x) = \frac{sin x}{x} \\&lt;br /&gt;
  h(x) = \frac{1 &amp;#8211; cosx}{x}&lt;br /&gt;
  \end{array}&lt;br /&gt;
$$&lt;br /&gt;
g(0) is undefined, but:&lt;br /&gt;
$$&lt;br /&gt;
  \begin{array}{1 1}&lt;br /&gt;
  \lim_{x \to 0} \frac{sin x}{x} = 1 \\&lt;br /&gt;
  \lim_{x \to 0} \frac{1 &amp;#8211; cos x}{x} = 0&lt;br /&gt;
  \end{array}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;These functions have a removable discontinuity at x = 0&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Infinite discontinuity&lt;/b&gt;&lt;br /&gt;
Consider \(\frac{1}{x}\):&lt;br /&gt;
$$&lt;br /&gt;
  \begin{array}{1 1}&lt;br /&gt;
    \lim_{x \to x_0^+} \frac{1}{x} = \infty \\&lt;br /&gt;
    \lim_{x \to x_0^-} \frac{1}{x} = -\infty&lt;br /&gt;
  \end{array}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Other (ugly) discontinuities&lt;/b&gt;&lt;br /&gt;
\(y = sin \frac{1}{x} \text{as} \; x \to 0\)&lt;br /&gt;
No left or right limit&lt;/p&gt;
&lt;h3&gt;Differential implies continuous theorem&lt;/h3&gt;
&lt;p&gt;If f is differentiable at \(x_0\), then x is continuous at \(x_0\)&lt;br /&gt;
&lt;b&gt;Proof:&lt;/b&gt;&lt;br /&gt;
$$&lt;br /&gt;
  \lim_{x \to x_0} f(x) &amp;#8211; f(x_0) = 0&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  \lim_{x \to x_0} \frac{f(x) &amp;#8211; f(x_0)}{x &amp;#8211; x_0} (x &amp;#8211; x_0) = f&amp;#8217;(x_0) . 0 = 0&lt;br /&gt;
$$&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=PyPLIESnG1M:mXbijT_mbqY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=PyPLIESnG1M:mXbijT_mbqY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=PyPLIESnG1M:mXbijT_mbqY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=PyPLIESnG1M:mXbijT_mbqY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=PyPLIESnG1M:mXbijT_mbqY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=PyPLIESnG1M:mXbijT_mbqY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=PyPLIESnG1M:mXbijT_mbqY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/PyPLIESnG1M" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-single-variable-calculus/week-1</feedburner:origLink></entry>
 
 <entry>
   <title>MIT OCW Single Variable Calculus</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/1Qu6x6UZT74/mit-single-variable-calculus" />
   <updated>2012-01-18T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-single-variable-calculus</id>
   <content type="html">&lt;p&gt;&lt;span class="caps"&gt;THIS&lt;/span&gt; IS A &lt;span class="caps"&gt;PLACEHOLDER&lt;/span&gt; SO &lt;span class="caps"&gt;THAT&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;INDEX&lt;/span&gt; &lt;span class="caps"&gt;APPEARS&lt;/span&gt; IN &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;PROJECT&lt;/span&gt; &lt;span class="caps"&gt;LIST&lt;/span&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=1Qu6x6UZT74:Hz3LsV5HILY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=1Qu6x6UZT74:Hz3LsV5HILY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=1Qu6x6UZT74:Hz3LsV5HILY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=1Qu6x6UZT74:Hz3LsV5HILY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=1Qu6x6UZT74:Hz3LsV5HILY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=1Qu6x6UZT74:Hz3LsV5HILY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=1Qu6x6UZT74:Hz3LsV5HILY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/1Qu6x6UZT74" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-single-variable-calculus</feedburner:origLink></entry>
 
 <entry>
   <title>D&amp;D Monster Tokens</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/TuJXTbRT6Xg/dungeons-and-dragons-monster-tokens" />
   <updated>2012-01-09T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/dungeons-and-dragons-monster-tokens</id>
   <content type="html">&lt;p&gt;Everyone knowns how much easier combat is to understand when you have some spatial aids. Wizards of the Coast and other gaming companies are pushing hard on minis, but they&amp;#8217;re fairly expensive and take up a lot of storage room. Did I also mention they happen to be expensive to collect a lot?&lt;/p&gt;
&lt;p&gt;As an alternative, you can use tokens, and make them at home. I used to think home-made tokens looked cheap, because the tokens I saw people use had hodge-podge artwork on them, in different styles and mediums, and there was no sense of cohesion.&lt;/p&gt;
&lt;p&gt;Which is why I decided to make my own tokens. I like to think I&amp;#8217;ve come up with a pretty streamline way to make tokens fast, and I&amp;#8217;m quickly expanding my repetoire.&lt;/p&gt;
&lt;p&gt;Here are the things you need:&lt;/p&gt;
&lt;p&gt;- One of these bad boys:&lt;br /&gt;
&lt;img src="/files/circle-punch.jpg" title="Scrapbooking paper circle punch" alt="Scrapbooking paper circle punch" /&gt;&lt;br /&gt;
which is a circle punch used in scrapbooking, available at any good craft store, including Michaels here in the &lt;span class="caps"&gt;USA&lt;/span&gt;. This will do for most medium sized creatures, but if you need to go larger, you can use one of these:&lt;br /&gt;
&lt;img src="/files/circle-cutter.jpg" title="Scrapbooking paper circle cutter" alt="Scrapbooking paper circle cutter" /&gt;&lt;br /&gt;
which is a circle cutter, and should do 1&amp;quot; &amp;#8211; 5&amp;quot; circles, which should be good for any monster you can come up with.&lt;br /&gt;
- Some contact paper, available at any stationary store.&lt;br /&gt;
- Some card stock&lt;br /&gt;
- A computer and a printer.&lt;/p&gt;
&lt;p&gt;Using these supplies, you can make your own tokens fairly quickly and easily. Now, I like to draw, and I&amp;#8217;m fairly good at it, so I draw my own tokens. For those of you who either don&amp;#8217;t have the time, inclination or skill to draw your own, I&amp;#8217;m making mine available for free.&lt;/p&gt;
&lt;p&gt;As you can see, the art is consistent, and the templates are pretty easy to use. Simply print the template onto card stock, contact both sides so you can write on them with dry erase markers, line up the circle punch and punch them out. Instant tokens.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m slowly adding more monsters as my adventuring party encounter them, so periodically check back for updated monsters.&lt;br /&gt;
Here are the monsters that I have currently:&lt;br /&gt;
- &lt;a href="http://www.timgittos.com/files/tokens/zombie.jpg"&gt;Zombie&lt;/a&gt;&lt;br /&gt;
- &lt;a href="http://www.timgittos.com/files/tokens/skeleton.jpg"&gt;Skeleton&lt;/a&gt;&lt;br /&gt;
- &lt;a href="http://www.timgittos.com/files/tokens/hobgoblin.jpg"&gt;Hobgoblin&lt;/a&gt;&lt;br /&gt;
- &lt;a href="http://www.timgittos.com/files/tokens/spider.jpg"&gt;Spider&lt;/a&gt;&lt;br /&gt;
- &lt;a href="http://www.timgittos.com/files/tokens/ghoul.jpg"&gt;Ghoul&lt;/a&gt;&lt;br /&gt;
- &lt;a href="http://www.timgittos.com/files/tokens/homunculus.jpg"&gt;Homunculus&lt;/a&gt;&lt;br /&gt;
- &lt;a href="http://www.timgittos.com/files/tokens/evilcleric.jpg"&gt;Evil cleric&lt;/a&gt;&lt;br /&gt;
- &lt;a href="http://www.timgittos.com/files/tokens/humanberzerker.jpg"&gt;Human berzerker&lt;/a&gt;&lt;br /&gt;
- Gelatinous cube (coming soon)&lt;br /&gt;
- Goblin (coming soon)&lt;br /&gt;
- Kobold (coming soon)&lt;/p&gt;
&lt;p&gt;(current as of 01-09-2012, and we play once a week, with new monsters twice a month or so)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=TuJXTbRT6Xg:SWrVQMPJwG8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=TuJXTbRT6Xg:SWrVQMPJwG8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=TuJXTbRT6Xg:SWrVQMPJwG8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=TuJXTbRT6Xg:SWrVQMPJwG8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=TuJXTbRT6Xg:SWrVQMPJwG8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=TuJXTbRT6Xg:SWrVQMPJwG8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=TuJXTbRT6Xg:SWrVQMPJwG8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/TuJXTbRT6Xg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/dungeons-and-dragons-monster-tokens</feedburner:origLink></entry>
 
 <entry>
   <title>MIT OCW Linear Algebra - Week 1</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/6U-oCPnN8SU/week-1" />
   <updated>2012-01-06T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-linear-algebra/week-1</id>
   <content type="html">&lt;h3&gt;Linear equations&lt;/h3&gt;
&lt;p&gt;n equations, n unknowns &amp;#8211; easy to solve.&lt;/p&gt;
&lt;p&gt;Example:&lt;br /&gt;
$$&lt;br /&gt;
  \begin{array}{1 1}&lt;br /&gt;
  2x &amp;#8211; y = 0 \\&lt;br /&gt;
  -x + 2y = 3&lt;br /&gt;
  \end{array}&lt;br /&gt;
$$&lt;br /&gt;
can be solved with matrices as follows:&lt;br /&gt;
$$&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  2 &amp;amp; -1 \\&lt;br /&gt;
  -1 &amp;amp; 2&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  x \\&lt;br /&gt;
  y&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  0 \\&lt;br /&gt;
  3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;The matrix of co-efficients will be called \(A\), the vector of unknowns will be called \(X\) and the resultant matrix will be called \(b\).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Row picture&lt;/b&gt;&lt;br /&gt;
&lt;img src="/images/la/graph01.gif" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The point of intersection is the solution to this pair of linear equations.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Column picture&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;We can reinterpret these two equations into a single matrix equation:&lt;br /&gt;
$$&lt;br /&gt;
  x \begin{bmatrix}&lt;br /&gt;
    2 \\&lt;br /&gt;
    -1&lt;br /&gt;
  \end{bmatrix} + y \begin{bmatrix}&lt;br /&gt;
    -1 \\&lt;br /&gt;
    2&lt;br /&gt;
  \end{bmatrix} = \begin{bmatrix}&lt;br /&gt;
    0 \\&lt;br /&gt;
    3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;Now the equation is asking us to find the correct linear combination of the columns, or vectors, that solves the equation.&lt;br /&gt;
The linear combination is the proportion of each vector that solves the equation.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/la/graph02.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Lets plug in the correct results from above, and take 1 of \(\begin{bmatrix}2\\-1\end{bmatrix}\) and 2 of \(\begin{bmatrix}-1\\2\end{bmatrix}\):&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/la/graph03.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, we get the answer \(b\), which is \(\begin{bmatrix}0\\3\end{bmatrix}\)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2&lt;/b&gt;&lt;br /&gt;
Now lets consider 3 equations with 3 unknowns:&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  \begin{array}{1 1}&lt;br /&gt;
    2x &amp;#8211; y = 0 \\&lt;br /&gt;
    -x + 2y &amp;#8211; z = -1 \\&lt;br /&gt;
    -3y + 4z = 4&lt;br /&gt;
  \end{array}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;Matrix form:&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  A =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    2 &amp;amp; -1 &amp;amp; 0 \\&lt;br /&gt;
    -1 &amp;amp; 2 &amp;amp; -1 \\&lt;br /&gt;
    0 &amp;amp; -3 &amp;amp; 4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \quad&lt;br /&gt;
  b =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    0 \\&lt;br /&gt;
    -1 \\&lt;br /&gt;
    4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;Row picture:&lt;/p&gt;
&lt;p&gt;A 3D cartesian axis with 3 planes that meet in a point. Omitting the plot due to the complexity of the problem.&lt;br /&gt;
This points to a weakness in this interpretation of the problem in higher dimensions.&lt;/p&gt;
&lt;p&gt;Column picture:&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  x&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  2 \\&lt;br /&gt;
  -1 \\&lt;br /&gt;
  0&lt;br /&gt;
  \end{bmatrix} + y&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  -1 \\&lt;br /&gt;
  2 \\&lt;br /&gt;
  -3&lt;br /&gt;
  \end{bmatrix} + z&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  0 \\&lt;br /&gt;
  -1 \\&lt;br /&gt;
  4&lt;br /&gt;
  \end{bmatrix} = &lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  0 \\&lt;br /&gt;
  -1 \\&lt;br /&gt;
  4&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;The solution is \(x = 0, y = 0, z = 1\), which is clearly seen from the matrices.&lt;/p&gt;
&lt;p&gt;Consider the case where we have a different &lt;span class="caps"&gt;RHS&lt;/span&gt;:&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  x&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  2 \\&lt;br /&gt;
  -1 \\&lt;br /&gt;
  0&lt;br /&gt;
  \end{bmatrix} + y&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  -1 \\&lt;br /&gt;
  2 \\&lt;br /&gt;
  -3&lt;br /&gt;
  \end{bmatrix} + z&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  0 \\&lt;br /&gt;
  -1 \\&lt;br /&gt;
  4&lt;br /&gt;
  \end{bmatrix} = &lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 \\&lt;br /&gt;
  1 \\&lt;br /&gt;
  -3&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;You can see the solution is \(x = 1, y = 1, z = 0\).&lt;/p&gt;
&lt;p&gt;Consider all &lt;span class="caps"&gt;RHS&lt;/span&gt; sides? Can we solve \(Ax = b\) for every b? To restate, do the linear combinations of the columns fill 3D space?&lt;br /&gt;
The answer for the above matrix A, the answer is yes. This means the matrix is non-singular and invertable.&lt;br /&gt;
If the answer is no, then the matrix is singular and non-invertable.&lt;/p&gt;
&lt;p&gt;For example, if the three vectors lie in the same plane, then the combinations will lie in the same plane &amp;#8211; but not all of 3D space.&lt;/p&gt;
&lt;p&gt;A matrix is singular and non-invertable if the columns are linearly independent from each other.&lt;/p&gt;
&lt;p&gt;Multiplying a matrix by a vector:&lt;br /&gt;
Column way, as opposed to the row way:&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  \begin{bmatrix} 2 &amp;amp; 5 \\ 1 &amp;amp; 3 \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix} 1 \\ 2 \end{bmatrix} &lt;br /&gt;
$$&lt;br /&gt;
$$&lt;br /&gt;
  = 1 \begin{bmatrix} 2 \\ 1 \end{bmatrix} + 2 \begin{bmatrix} 5 \\ 3 \end{bmatrix}&lt;br /&gt;
$$&lt;br /&gt;
$$&lt;br /&gt;
  = \begin{bmatrix} 12 \\ 7 \end{bmatrix}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;So you can see that \(Ax\) is a combination of the columns of \(A\)&lt;/p&gt;
&lt;h3&gt;Matrix Elimination&lt;/h3&gt;
&lt;p&gt;Discovered by Gauss.&lt;/p&gt;
&lt;p&gt;We will be working from the following example equations:&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  \begin{array}{1 3}&lt;br /&gt;
    x + 2y + z = 2 \\&lt;br /&gt;
    3x + 8y + z = 12 \\&lt;br /&gt;
    4y + z = 2&lt;br /&gt;
  \end{array}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;the coefficients of which can be represented by the following matrix:&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  A = \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
    3 &amp;amp; 8 &amp;amp; 1 \\&lt;br /&gt;
    0 &amp;amp; 4 &amp;amp; 1&lt;br /&gt;
    \end{bmatrix}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;the answer with:&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  b = \begin{bmatrix}&lt;br /&gt;
    2 \\&lt;br /&gt;
    12 \\&lt;br /&gt;
    2&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;and the full equation represented by:&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
  Ax = b&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;To begin, the purpose of elimination is to get rid of as many unknowns as we can and then solve for the remaining unknown.&lt;br /&gt;
The first step in this case would be to subtract \(x + 2y + z = 2\) from \(3x + 8y + z\) with the goal of eliminating the \(x\) variable.&lt;/p&gt;
&lt;p&gt;Firstly, declare the \(x\) coefficient in the first row of matrix \(A\) to be the pivot. Then find the multiple of the pivot required to eliminate it. In this case, it&amp;#8217;s 3. Then subtract the first row multiplied by the multiple from the second row. This will result in:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 2 &amp;amp; -2 \\&lt;br /&gt;
  0 &amp;amp; 4 &amp;amp; 1&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This has eliminated \(x\) from the second row, the [2, 1] position. The next step would be to eliminate \(x\) from the [3, 1] position, however there is no need to do this, as it is already 0.&lt;/p&gt;
&lt;p&gt;Next, eliminate \(y\) from the third row. Set the pivot to be the \(y\) coefficient in \(A\) and find the multiple required to eliminate it. The multiple is 2. Then subtract the second row multiplied by the multiple from the third row:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 2 &amp;amp; -2 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 5&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This results in a type of matrix called an upper-triangular matrix. This is the form of matrix we need to complete this form of elimination. We can call this matrix \(u\).&lt;/p&gt;
&lt;p&gt;Note: pivots can&amp;#8217;t be 0.&lt;/p&gt;
&lt;p&gt;This process will fail if there&amp;#8217;s a 0 in a pivot position. This will require reorganizing the matrix if possible, so that there is a non-zero number in the pivot position. If you can&amp;#8217;t find 3 pivots, the matrix is non-invertable and the solution cannot be found.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Back substitution&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;After finding the multiples, we can apply the same algorithm to the right hand side of the equation:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  b = &lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
  2 \\ 12 \\ 2&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \quad&lt;br /&gt;
  \rightarrow&lt;br /&gt;
  \quad&lt;br /&gt;
  b = &lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
  2 \\ 6 \\ 2&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \quad&lt;br /&gt;
  \rightarrow&lt;br /&gt;
  \quad&lt;br /&gt;
  b =&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
  2 \\ 6 \\ -10&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This leaves us with the augmented matrix:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 2 &amp;amp; -2 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 5&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \left|&lt;br /&gt;
  \begin{matrix}&lt;br /&gt;
  2 \\ 6 \\ -10&lt;br /&gt;
  \end{matrix}&lt;br /&gt;
  \right.&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;and we can see that we have the equation \(5z = -10\) and that \(z = -2\).&lt;/p&gt;
&lt;p&gt;We can then substitute that back in to the above equation for \(2y &amp;#8211; 2(-2) = 6\) to get \(y = 1\), and then substitute that back into the first equation for \(x + 2(1) + 1(-2) = 2\) and get \(x = 2\).&lt;/p&gt;
&lt;p&gt;Thus using elimination and substitution we have solved the equation with \(x = 2\), \(y = 1\) and  \(z = -2\)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Matrices&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Now we&amp;#8217;re going to represent the above calculation in matrix form. We want to perform elimination on the following matrix:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
  3 &amp;amp; 8 &amp;amp; 1 \\&lt;br /&gt;
  0 &amp;amp; 4 &amp;amp; 1 \\&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;First, we want to find the matrix that will subtract 3 times row 1 from row 2, and leaves the other rows. So we want to find the matrix \(X\) that solves the following:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  X \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
    3 &amp;amp; 8 &amp;amp; 1 \\&lt;br /&gt;
    0 &amp;amp; 4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \quad = \quad&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
    0 &amp;amp; 2 &amp;amp; -2 \\&lt;br /&gt;
    0 &amp;amp; 4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Lets go back to the concept of multiplying matrices first, in order to solve this intuitively.&lt;/p&gt;
&lt;p&gt;Consider this problem:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  x_{1,1} &amp;amp; y_{1,2} &amp;amp; z_{1,3} \\&lt;br /&gt;
  x_{2,1} &amp;amp; y_{2,2} &amp;amp; z_{2,3} \\&lt;br /&gt;
  x_{3,1} &amp;amp; y_{3,2} &amp;amp; z_{3,3}&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  4 \\ 5 \\ 6&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;This is saying take 4 of the first column, 5 of the second column and 6 of the third column:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    4 (x_{1,1} + x_{2,1} + x_{3,1}) \\&lt;br /&gt;
    5 (y_{1,2} + y_{2,2} + y_{3,2}) \\&lt;br /&gt;
    6 (z_{1,3} + z_{2,3} + z_{3,3})&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  = \begin{bmatrix}&lt;br /&gt;
  12x \\&lt;br /&gt;
  15y \\&lt;br /&gt;
  18z&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;which is a combination of the columns of the matrix. This will result in a column vector.&lt;/p&gt;
&lt;p&gt;Where as this problem:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  4 &amp;amp; 5 &amp;amp; 6&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  x_{1,1} &amp;amp; y_{1,2} &amp;amp; z_{1,3} \\&lt;br /&gt;
  x_{2,1} &amp;amp; y_{2,2} &amp;amp; z_{2,3} \\&lt;br /&gt;
  x_{3,1} &amp;amp; y_{3,2} &amp;amp; z_{3,3}&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;is saying &amp;quot;take 4 of the first row, 5 of the second row and 6 of the third row:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \left[&lt;br /&gt;
  \begin{array}{3 1}&lt;br /&gt;
  4 (x_{1,1} + y_{1,2} + z_{1,3}) + \\&lt;br /&gt;
  5 (x_{2,1} + y_{2,2} + z_{2,3}) + \\&lt;br /&gt;
  6 (x_{3,1} + y_{3,2} + z_{3,3})&lt;br /&gt;
  \end{array}&lt;br /&gt;
  \right]&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  = \begin{bmatrix}&lt;br /&gt;
  15x &amp;amp; 15y &amp;amp; 15z&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;which is a combination of the rows of the matrix. This will result in a row vector.&lt;/p&gt;
&lt;p&gt;Now going back to the problem at hand:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  X \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
    3 &amp;amp; 8 &amp;amp; 1 \\&lt;br /&gt;
    0 &amp;amp; 4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \quad = \quad&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
    0 &amp;amp; 2 &amp;amp; -2 \\&lt;br /&gt;
    0 &amp;amp; 4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;You can see that we need 1 of the first row, and 1 of the last row to solve this equation. Thus, we can see that:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  X =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
  x_{2,1} &amp;amp; x_{2,2} &amp;amp; x_{2,3} \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;because if you consider \(\begin{bmatrix} 1 &amp;amp; 0 &amp;amp; 0 \end{bmatrix}\) as a row vector, that will take 1 of the first row of the matrix and none of the second and third rows of the matrix, which is what the first row of the answer is. Likewise for the last row.&lt;/p&gt;
&lt;p&gt;Now we need the row that will subtract 3 of the first row from the second row. We can see the answer is:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  X = &lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
  -3 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We can also call this matrix \(E_{2,1}\), the elimination matrix to eliminate the 2,1 position of the co-efficient matrix.&lt;/p&gt;
&lt;p&gt;Now we need to represent step 2, which will eliminate the position 3,2, matrix \(E_{3,2}\):&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  E_{3,2}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
    0 &amp;amp; 2 &amp;amp; -2 \\&lt;br /&gt;
    0 &amp;amp; 4 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \quad = \quad&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
    1 &amp;amp; 2 &amp;amp; 1 \\&lt;br /&gt;
    0 &amp;amp; 2 &amp;amp; -2 \\&lt;br /&gt;
    0 &amp;amp; 0 &amp;amp; 5&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Using the above steps, we know that:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  E_{3,2} =&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
  0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
  0 &amp;amp; -2 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;We can now roll both steps into a single step, a single matrix \(E\) that does all the steps at once.&lt;br /&gt;
Firstly, lets represet what we did in an equation:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  E_{3,2}(E_{2,1}A) = u&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;where u is the final result of the elimination, before we started the back substitution.&lt;/p&gt;
&lt;p&gt;Given that matrix multiplication is associative, we can represent that as:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  (E_{3,2}E_{2,1})A = u&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;which will give E:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
  0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
  0 &amp;amp; -2 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
  -3 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
  0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \quad = \quad&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
  -3 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
  6 &amp;amp; -2 &amp;amp; 1&lt;br /&gt;
  \end{bmatrix} &lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;However, that&amp;#8217;s not the optimal way. Lets consider the equation again:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  (E_{3,2}E_{2,1})A = u&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;Lets consider, instead of how we&amp;#8217;d get from A to u, but from u to A, using &lt;b&gt;inverses&lt;/b&gt;. That&amp;#8217;s a topic for next time.&lt;/p&gt;
&lt;p&gt;Note: If we needed to exchange rows, we would have done so using a permutation matrix. This is easy to derrive by thinking about it in terms of functions of rows in terms of row exchanges, and columns in terms of column exchanges, as per the above examples.&lt;br /&gt;
For example, exchanging rows in a 2&amp;#215;2 matrix:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  0 &amp;amp; 1 \\&lt;br /&gt;
  1 &amp;amp; 0 \\&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  a &amp;amp; b \\&lt;br /&gt;
  c &amp;amp; d&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \quad = \quad&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  c &amp;amp; d \\&lt;br /&gt;
  a &amp;amp; b&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;
&lt;p&gt;and exchanging columns in a 2&amp;#215;2 matrix:&lt;/p&gt;
&lt;p&gt;\[&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  a &amp;amp; b \\&lt;br /&gt;
  c &amp;amp; d&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  0 &amp;amp; 1 \\&lt;br /&gt;
  1 &amp;amp; 0&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
  \quad = \quad&lt;br /&gt;
  \begin{bmatrix}&lt;br /&gt;
  b &amp;amp; a \\&lt;br /&gt;
  d &amp;amp; c&lt;br /&gt;
  \end{bmatrix}&lt;br /&gt;
\]&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=6U-oCPnN8SU:tzLSwV1eZ2o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=6U-oCPnN8SU:tzLSwV1eZ2o:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=6U-oCPnN8SU:tzLSwV1eZ2o:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=6U-oCPnN8SU:tzLSwV1eZ2o:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=6U-oCPnN8SU:tzLSwV1eZ2o:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=6U-oCPnN8SU:tzLSwV1eZ2o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=6U-oCPnN8SU:tzLSwV1eZ2o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/6U-oCPnN8SU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-linear-algebra/week-1</feedburner:origLink></entry>
 
 <entry>
   <title>MIT OCW Linear Algebra</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/YRlOn6mqfi4/mit-linear-algebra" />
   <updated>2012-01-06T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/mit-linear-algebra</id>
   <content type="html">&lt;p&gt;&lt;span class="caps"&gt;THIS&lt;/span&gt; IS A &lt;span class="caps"&gt;PLACEHOLDER&lt;/span&gt; SO &lt;span class="caps"&gt;THAT&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;INDEX&lt;/span&gt; &lt;span class="caps"&gt;APPEARS&lt;/span&gt; IN &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;PROJECT&lt;/span&gt; &lt;span class="caps"&gt;LIST&lt;/span&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=YRlOn6mqfi4:bSqnI6ok8dI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=YRlOn6mqfi4:bSqnI6ok8dI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=YRlOn6mqfi4:bSqnI6ok8dI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=YRlOn6mqfi4:bSqnI6ok8dI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=YRlOn6mqfi4:bSqnI6ok8dI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=YRlOn6mqfi4:bSqnI6ok8dI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=YRlOn6mqfi4:bSqnI6ok8dI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/YRlOn6mqfi4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/mit-linear-algebra</feedburner:origLink></entry>
 
 <entry>
   <title>2011 In Review, And a Look Forward to 2012</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/9IIDPSFbzdA/2011-in-review-and-a-look-forward-to-2012" />
   <updated>2012-01-02T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/blog/2011-in-review-and-a-look-forward-to-2012</id>
   <content type="html">&lt;p&gt;Although I didn&amp;#8217;t start out with a plan for 2011, I&amp;#8217;m going to perform a brief review of the last year and outline some of the remarkable things that happened to me. This will hopefully help me feel like I&amp;#8217;ve achieved something significant.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Got married (technically that happened at the end of 2010, but I&amp;#8217;m going to include it here)&lt;/li&gt;
	&lt;li&gt;Moved to the US permanently&lt;/li&gt;
	&lt;li&gt;Started a new job at an Austin based startup&lt;/li&gt;
	&lt;li&gt;Made some new friends, and started playing D&amp;amp;D again (this is something I didn&amp;#8217;t think I could ever do again, so it&amp;#8217;s a good thing for me)&lt;/li&gt;
	&lt;li&gt;Visited India for the first time&lt;/li&gt;
	&lt;li&gt;Completed 2 courses in Stanfords experimental online university courses &amp;#8211; Introduction to Artificial Intelligence, and Machine Learning. This lead me to watch some lectures and learn material I&amp;#8217;ve been meaning to get around to for a few years&lt;/li&gt;
	&lt;li&gt;Realized the importance of working on only one thing at a time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last one, I think, is the most important to my future growth.&lt;/p&gt;
&lt;p&gt;Up until now, I&amp;#8217;ve been trying to do too many things at once, and thus got nothing done. I&amp;#8217;ve always been saying I&amp;#8217;ll concentrate on one thing at a time, but I never follow through.&lt;/p&gt;
&lt;p&gt;The Stanford online classes helped me finally follow through with that goal, and for 2 months, I focused only on completing those classes. It opened my eyes to just how important it is to work on only one thing at a time.&lt;/p&gt;
&lt;p&gt;Due to this, I am devoting the entirety of 2012 to my artwork, and I&amp;#8217;m setting some specific goals to measure my progress. After all, if you&amp;#8217;re not measuring it, you can&amp;#8217;t learn from it.&lt;/p&gt;
&lt;p&gt;These goals are as follows:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Finish the 4&amp;#8242;&amp;#215;5&amp;#8242; airbrush portrait of myself and my wife for my mother-in-law.&lt;/li&gt;
	&lt;li&gt;Sell a piece of artwork&lt;/li&gt;
	&lt;li&gt;Earn enough money through art on the side to buy a Cintiq&lt;/li&gt;
	&lt;li&gt;Submit art for Spectrum 20 (being accepted would be fantastic, but submitting is good enough)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This isn&amp;#8217;t the full list of goals, but it is a list of landmarks to mark my progress. I&amp;#8217;m hoping that I&amp;#8217;ll get the first 2 done before June.&lt;br /&gt;
At the end of 2012, I&amp;#8217;ll review how I did with these goals.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=9IIDPSFbzdA:uXs7Fb82I4g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=9IIDPSFbzdA:uXs7Fb82I4g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=9IIDPSFbzdA:uXs7Fb82I4g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=9IIDPSFbzdA:uXs7Fb82I4g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=9IIDPSFbzdA:uXs7Fb82I4g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=9IIDPSFbzdA:uXs7Fb82I4g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=9IIDPSFbzdA:uXs7Fb82I4g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/9IIDPSFbzdA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/blog/2011-in-review-and-a-look-forward-to-2012</feedburner:origLink></entry>
 
 <entry>
   <title>Things that Suck</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/MfVqjXXAlIM/things-that-suck" />
   <updated>2011-12-16T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/blog/things-that-suck</id>
   <content type="html">&lt;p&gt;I do a lot of reading about startups and entrepreneurship. A common theme on the subject of getting started is finding problems to solve. &amp;#8220;Easier said than done&amp;#8221;, I&amp;#8217;ve always thought. People in the tech startup world love to claim that ideas are cheap and easy, execution is where it counts. Ideas weren&amp;#8217;t cheap and easy to me, until I learned a trick.&lt;/p&gt;
&lt;p&gt;Startup literature writes that you should find meaningful problems to solve in order to start your startup. That seems kind of abstract to me. If I had a meaningful problem, usually I&amp;#8217;ve already solved it myself.&lt;br /&gt;
Getting more specific, people bring up &amp;#8220;pain points.&amp;#8221; Find something in your life that is a &amp;#8220;pain point&amp;#8221; and fix that, and chances are, other people have the same &amp;#8220;pain point&amp;#8221; and you can help them solve it. Again, that&amp;#8217;s a little abstract. What causes me pain in my life? Not much.&lt;/p&gt;
&lt;p&gt;While dwelling on the meaning of &amp;#8220;pain point&amp;#8221;, I came up with a rephrasing and a quick acid test. A pain point is something that makes you say &amp;#8220;Man, this sucks.&amp;#8221;&lt;/p&gt;
&lt;p&gt;&amp;#8220;Driving home in traffic sucks&amp;#8221;&lt;br /&gt;
&amp;#8220;Planning a wedding sucks&amp;#8221;&lt;br /&gt;
&amp;#8220;Changing travel plans sucks&amp;#8221;&lt;br /&gt;
&amp;#8220;Lost luggage sucks&amp;#8221;&lt;/p&gt;
&lt;p&gt;Something is a &amp;#8220;pain point&amp;#8221; if doing it, or experiencing it, or fixing it makes you think &amp;#8220;Man, this sucks.&amp;#8221;&lt;/p&gt;
&lt;p&gt;If something sucks, and you can fix it, then you start to put the idea through the whole &amp;#8220;will people pay for this&amp;#8221; wringer.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=MfVqjXXAlIM:zQqXDRaouAc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=MfVqjXXAlIM:zQqXDRaouAc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=MfVqjXXAlIM:zQqXDRaouAc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=MfVqjXXAlIM:zQqXDRaouAc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=MfVqjXXAlIM:zQqXDRaouAc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=MfVqjXXAlIM:zQqXDRaouAc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=MfVqjXXAlIM:zQqXDRaouAc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/MfVqjXXAlIM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/blog/things-that-suck</feedburner:origLink></entry>
 
 <entry>
   <title>Stanford Online Artificial Intelligence Class</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/-vtX1F7dIy8/stanford-artificial-intelligence" />
   <updated>2011-12-15T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/stanford-artificial-intelligence</id>
   <content type="html">&lt;h2&gt;What is this?&lt;/h2&gt;
&lt;p&gt;Stanford is running &lt;a href="http://ai-class.com"&gt;an artificial intelligence class&lt;/a&gt; during the summer of 2011. I am participating in this class, and this page will track my progress. I will be posting things like lecture notes and additional reading/research.&lt;/p&gt;
&lt;p&gt;I hope to both provide help to other people who are running the class, information to people who may have missed the class, and accountability for myself to follow this class through to completion.&lt;/p&gt;
&lt;h3&gt;Update: December 15, 2011&lt;/h3&gt;
&lt;p&gt;With the class come to a close, I can publish all of my individual lecture notes in a single document:&lt;br /&gt;
&lt;a href="http://timgittos.com/files/ai-class/notes.pdf"&gt;Entire course notes&lt;/a&gt;&lt;br /&gt;
and the solution to the last week&amp;#8217;s programming exercise:&lt;br /&gt;
&lt;a href="http://timgittos.com/files/ai-class/aiclassnlp1.rb"&gt;aiclassnlp1.rb&lt;/a&gt; &amp;#8211; solution for the first question&lt;br /&gt;
&lt;a href="http://timgittos.com/files/ai-class/aiclassnlp2.rb"&gt;aiclassnlp2.rb&lt;/a&gt; &amp;#8211; solution for the second question&lt;br /&gt;
&lt;a href="http://timgittos.com/files/ai-class/corpus.txt"&gt;corpus.txt&lt;/a&gt; &amp;#8211; training corpus for the second question (Flatland by Edwin A. Abbot, from &lt;a href="http://gutenberg.org"&gt;Project Gutenberg&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://timgittos.com/files/ai-class/input.txt"&gt;input.txt&lt;/a&gt; &amp;#8211; input for the second question (from the notes on the video)&lt;/p&gt;
&lt;h2&gt;Week 1&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-01.pdf"&gt;Lecture notes&lt;/a&gt; for the first week&amp;#8217;s lessons.&lt;/p&gt;
&lt;h2&gt;Week 2&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-02.pdf"&gt;Lecture notes&lt;/a&gt; for the second week&amp;#8217;s lessons.&lt;br /&gt;
Also, the homework for Week 2 really kicked my butt. I had some issues getting my head around some of the probability, so here are some resources I&amp;#8217;m finding useful:&lt;br /&gt;
- &lt;a href="http://www.reddit.com/r/aiclass/comments/lrojo/understanding_bayes_rule_intuitively_without/"&gt;http://www.reddit.com/r/aiclass/comments/lrojo/understanding_bayes_rule_intuitively_without/&lt;/a&gt;&lt;br /&gt;
- &lt;a href="http://www.reddit.com/r/aiclass/comments/lm7g7/dseparation_and_the_bayes_ball_algorithm/"&gt;http://www.reddit.com/r/aiclass/comments/lm7g7/dseparation_and_the_bayes_ball_algorithm/&lt;/a&gt;&lt;br /&gt;
- &lt;a href="http://postimage.org/image/udh7nv217/"&gt;http://postimage.org/image/udh7nv217/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Week 3&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-03.pdf"&gt;Lecture notes&lt;/a&gt; for the third week&amp;#8217;s lessons.&lt;/p&gt;
&lt;h2&gt;Week 4&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-04.pdf"&gt;Lecture notes&lt;/a&gt; for the fourth week&amp;#8217;s lessons.&lt;/p&gt;
&lt;h2&gt;Week 5&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-05.pdf"&gt;Lecture notes&lt;/a&gt; for the fifth week&amp;#8217;s lessons.&lt;/p&gt;
&lt;h2&gt;Week 6&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-06.pdf"&gt;Lecture notes&lt;/a&gt; for the sixth week&amp;#8217;s lessons.&lt;/p&gt;
&lt;h2&gt;Week 7&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-07.pdf"&gt;Lecture notes&lt;/a&gt; for the seventh&amp;#8217;s week&amp;#8217;s lessons.&lt;/p&gt;
&lt;h2&gt;Week 8&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-08.pdf"&gt;Lecture notes&lt;/a&gt; for the eighth week&amp;#8217;s lessons.&lt;/p&gt;
&lt;p&gt;This week, we also (kind of) learn how the Kinect does it&amp;#8217;s thing. Kind of awesome.&lt;/p&gt;
&lt;h2&gt;Week 9&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-09.txt"&gt;Lecture notes&lt;/a&gt; for the ninth week&amp;#8217;s lessons.&lt;/p&gt;
&lt;p&gt;These notes are in txt format because I had to take the notes on a laptop and not my iPad as I normally do.&lt;/p&gt;
&lt;h2&gt;Week 10&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://timgittos.com/files/ai-class/notes-week-10.pdf"&gt;Lecture notes&lt;/a&gt; for the tenth week&amp;#8217;s lessons.&lt;/p&gt;
&lt;p&gt;This week we also got to do optional programming assignments. Here are my solutions in Ruby (1.91):&lt;br /&gt;
&lt;a href="http://timgittos.com/files/ai-class/aiclassnlp1.rb"&gt;aiclassnlp1.rb&lt;/a&gt; &amp;#8211; solution for the first question&lt;br /&gt;
&lt;a href="http://timgittos.com/files/ai-class/aiclassnlp2.rb"&gt;aiclassnlp2.rb&lt;/a&gt; &amp;#8211; solution for the second question&lt;br /&gt;
&lt;a href="http://timgittos.com/files/ai-class/corpus.txt"&gt;corpus.txt&lt;/a&gt; &amp;#8211; training corpus for the second question (Flatland by Edwin A. Abbot, from &lt;a href="http://gutenberg.org"&gt;Project Gutenberg&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://timgittos.com/files/ai-class/input.txt"&gt;input.txt&lt;/a&gt; &amp;#8211; input for the second question (from the notes on the video)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=-vtX1F7dIy8:lb_Y2ndFECo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=-vtX1F7dIy8:lb_Y2ndFECo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=-vtX1F7dIy8:lb_Y2ndFECo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=-vtX1F7dIy8:lb_Y2ndFECo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=-vtX1F7dIy8:lb_Y2ndFECo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=-vtX1F7dIy8:lb_Y2ndFECo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=-vtX1F7dIy8:lb_Y2ndFECo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/-vtX1F7dIy8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/stanford-artificial-intelligence</feedburner:origLink></entry>
 
 <entry>
   <title>Stanford Online Machine Learning Class</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/bpEHzvAF4oM/stanford-machine-learning" />
   <updated>2011-12-11T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/stanford-machine-learning</id>
   <content type="html">&lt;h2&gt;What is this?&lt;/h2&gt;
&lt;p&gt;Stanford is running &lt;a href="http://ml-class.com"&gt;a machine learning class&lt;/a&gt; during the summer of 2011. I am participating in this class, and this page will track my progress. I will be posting things like lecture notes and additional reading/research.&lt;/p&gt;
&lt;p&gt;I hope to both provide help to other people who are running the class, information to people who may have missed the class, and accountability for myself to follow this class through to completion.&lt;/p&gt;
&lt;h2&gt;Week 1&lt;/h2&gt;
&lt;p&gt;&lt;a href="/files/ml-class/notes-week-01.pdf"&gt;Lecture notes&lt;/a&gt; for the first week&amp;#8217;s lessons.&lt;/p&gt;
&lt;h2&gt;Week 2&lt;/h2&gt;
&lt;p&gt;&lt;a href="/files/ml-class/notes-week-02.pdf"&gt;Lecture notes&lt;/a&gt; for the second week&amp;#8217;s lessons.&lt;br /&gt;
&lt;a href="/"&gt;Programming exercise&lt;/a&gt; posted in the second week. (I&amp;#8217;ll put these up at the end of the course, considering you can submit late)&lt;/p&gt;
&lt;h3&gt;Week 3&lt;/h3&gt;
&lt;p&gt;&lt;a href="/files/ml-class/notes-week-03.pdf"&gt;Lecture notes&lt;/a&gt; for the third week&amp;#8217;s lessons.&lt;br /&gt;
&lt;a href="/"&gt;Programming exercise&lt;/a&gt; posted in the third week. (I&amp;#8217;ll put these up at the end of the course, considering you can submit late)&lt;br /&gt;
&lt;a href="http://david-hu.com/2011/11/02/how-khan-academy-is-using-machine-learning-to-assess-student-mastery.html"&gt;Practical classifying with logistic regression&lt;/a&gt; &amp;#8211; an interesting write up about how &lt;a href="http://www.khanacademy.org"&gt;Khan Academy&lt;/a&gt; uses logistic regression to assess student mastery through a course.&lt;/p&gt;
&lt;h3&gt;Week 4 &amp;amp; 5&lt;/h3&gt;
&lt;p&gt;Both weeks 4 &amp;amp; 5 are about Neural Networks, and due to a change in the structure of week 4 a little into week 5, I&amp;#8217;ve rolled these two weeks into one.&lt;/p&gt;
&lt;p&gt;&lt;a href="/files/ml-class/notes-week-04-05.pdf"&gt;Lecture notes&lt;/a&gt; for the fourth and fifth week&amp;#8217;s lessons.&lt;br /&gt;
&lt;a href="/"&gt;Programming exercise&lt;/a&gt; posted in the fourth week and the &lt;a href="/"&gt;programming exercise&lt;/a&gt; for the fifth week. (I&amp;#8217;ll put these up at the end of the course, considering you can submit late)&lt;/p&gt;
&lt;p&gt;Also, I want to say that these two weeks&amp;#8217; programming exercises were to me the most interesting. Not only did we achieve a real, practical goal (recognizing hand written digits), but we got some insight about how to represent data in machine vision problems.&lt;br /&gt;
Week 4 was to implement forward propagation, and week 5 was backward propagation. In the end you end up with a neural network that can classify hand written digets that you built and trained from scratch yourself. Very cool.&lt;/p&gt;
&lt;h3&gt;Week 6&lt;/h3&gt;
&lt;p&gt;&lt;a href="/files/ml-class/notes-week-06.pdf"&gt;Lecture notes&lt;/a&gt; for the sixth week&amp;#8217;s lessons.&lt;br /&gt;
&lt;a href="/"&gt;Programming exercise&lt;/a&gt; posted in the sixth week. (I&amp;#8217;ll put these up at the end of the course, considering you can submit late)&lt;/p&gt;
&lt;h3&gt;Week 7&lt;/h3&gt;
&lt;p&gt;&lt;a href="/files/ml-class/notes-week-07.pdf"&gt;Lecture notes&lt;/a&gt; for the seventh week&amp;#8217;s lessons.&lt;br /&gt;
&lt;a href="/"&gt;Programming exercise&lt;/a&gt; posted in the seventh week. (I&amp;#8217;ll put these up at the end of the course, considering you can submit late)&lt;/p&gt;
&lt;h3&gt;Week 8&lt;/h3&gt;
&lt;p&gt;&lt;a href="/files/ml-class/notes-week-08.pdf"&gt;Lecture notes&lt;/a&gt; for the eighth week&amp;#8217;s lessons.&lt;br /&gt;
&lt;a href="/"&gt;Programming exercise&lt;/a&gt; posted in the eighth week. (I&amp;#8217;ll put these up at the end of the course, considering you can submit late)&lt;/p&gt;
&lt;h3&gt;Week 9&lt;/h3&gt;
&lt;p&gt;&lt;a href="/files/ml-class/notes-week-09.pdf"&gt;Lecture notes&lt;/a&gt; for the nineth week&amp;#8217;s lessons.&lt;br /&gt;
&lt;a href="/"&gt;Programming exercise&lt;/a&gt; posted in the nineth week. (I&amp;#8217;ll put these up at the end of the course, considering you can submit late)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bpEHzvAF4oM:1dGJpzCQWr0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bpEHzvAF4oM:1dGJpzCQWr0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=bpEHzvAF4oM:1dGJpzCQWr0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bpEHzvAF4oM:1dGJpzCQWr0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=bpEHzvAF4oM:1dGJpzCQWr0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bpEHzvAF4oM:1dGJpzCQWr0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=bpEHzvAF4oM:1dGJpzCQWr0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/bpEHzvAF4oM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/stanford-machine-learning</feedburner:origLink></entry>
 
 <entry>
   <title>Time</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/EVsbQvZOLos/time" />
   <updated>2011-11-08T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/blog/time</id>
   <content type="html">&lt;p&gt;&lt;iframe src="http://player.vimeo.com/video/31455885?title=0&amp;amp;byline=0&amp;amp;portrait=0&amp;amp;color=f1f1ef" width="960" height="540" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;a href="http://thisismadebyhand.com/film/the_knife_maker"&gt;The Knife Maker&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Firstly, this film resonates with me strongly. It&amp;#8217;s how I feel about my work, and the hobbies I choose to invest my time in.&lt;/p&gt;
&lt;p&gt;One of my favorite insights from the HN thread I found this in: &amp;#8220;Time must be used up. You don&amp;#8217;t get to just stop using your time until you have something in particular you want to use it for. If making something by hand is rewarding to you, and someone else will pay you for it then it&amp;#8217;s probably a good use of your time.&amp;#8221;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=EVsbQvZOLos:FQBvFASdKPI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=EVsbQvZOLos:FQBvFASdKPI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=EVsbQvZOLos:FQBvFASdKPI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=EVsbQvZOLos:FQBvFASdKPI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=EVsbQvZOLos:FQBvFASdKPI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=EVsbQvZOLos:FQBvFASdKPI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=EVsbQvZOLos:FQBvFASdKPI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/EVsbQvZOLos" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/blog/time</feedburner:origLink></entry>
 
 <entry>
   <title>Rails 3.1 Model Property Name Gotcha</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/pPmAD4KIOPQ/rails-model-property-name-gotcha" />
   <updated>2011-10-28T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/blog/rails-model-property-name-gotcha</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re trying to instantiate a Rails model and you keep getting &lt;em&gt;nil&lt;/em&gt; back instead of an instance of that model, chances are you have done something dumb like try to create a property on that model called &amp;#8220;class&amp;#8221;, or something equally ill-advised.&lt;/p&gt;
&lt;p&gt;I haven&amp;#8217;t tested this for all Ruby keywords, but chances are good that if the build in Object class has an instance property by the same name as one of your model properties, you&amp;#8217;re going to run into trouble.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s obvious when you&amp;#8217;re not dealing with the consequences, but when you&amp;#8217;re sitting there in a console and your .new instantiation is returning &lt;em&gt;nil&lt;/em&gt;, this get pretty confusing.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=pPmAD4KIOPQ:2RPiitMd12M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=pPmAD4KIOPQ:2RPiitMd12M:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=pPmAD4KIOPQ:2RPiitMd12M:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=pPmAD4KIOPQ:2RPiitMd12M:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=pPmAD4KIOPQ:2RPiitMd12M:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=pPmAD4KIOPQ:2RPiitMd12M:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=pPmAD4KIOPQ:2RPiitMd12M:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/pPmAD4KIOPQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/blog/rails-model-property-name-gotcha</feedburner:origLink></entry>
 
 <entry>
   <title>Games as Platforms</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/O7G5-OvGyd4/games-as-platforms" />
   <updated>2011-10-18T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/blog/games-as-platforms</id>
   <content type="html">&lt;p&gt;I just read &lt;a href="http://www.thatsaterribleidea.com/2011/10/mojang-up-minecraft-down.html"&gt;an article about Minecraft&amp;#8217;s direction away from a platform towards a computer game&lt;/a&gt; , and couldn&amp;#8217;t help thinking of one of my recent posts &lt;a href="http://www.timgittos.com/blog/platforms-and-sandboxes/"&gt;about businesses doing the opposite&lt;/a&gt; . If anything, it reinforces the concept of a platform for inverting the responsibility of creating value.&lt;/p&gt;
&lt;p&gt;I know I&amp;#8217;d much rather sell a game that makes money by itself, and enable others to create value for it by modding it. Hell, you could even let content creators earn money and take a commission. &lt;br /&gt;
I guess the only thing you need to be aware of is becoming a lame middleware vendor instead of a consumer product vendor.&lt;/p&gt;
&lt;p&gt;Platform as product first, then extendable by the community.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=O7G5-OvGyd4:BUns02AnO7g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=O7G5-OvGyd4:BUns02AnO7g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=O7G5-OvGyd4:BUns02AnO7g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=O7G5-OvGyd4:BUns02AnO7g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=O7G5-OvGyd4:BUns02AnO7g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=O7G5-OvGyd4:BUns02AnO7g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=O7G5-OvGyd4:BUns02AnO7g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/O7G5-OvGyd4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/blog/games-as-platforms</feedburner:origLink></entry>
 
 <entry>
   <title>WebGL Book</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/aciKBCk0YkA/webgl" />
   <updated>2011-10-13T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/articles/graphics/webgl-book/webgl</id>
   <content type="html">&lt;h2&gt;Status&lt;/h2&gt;
&lt;p&gt;The book is still very much in the planning stages. There are a few fundamental topics that I&amp;#8217;m still a little fuzzy about (deferred shading for lighting/bump mapping, etc mostly), and I&amp;#8217;m still researching these topics. Once I am a little more well informed, I will begin outlining the book and writing it.&lt;/p&gt;
&lt;p&gt;Updates will be pushed through my &lt;span class="caps"&gt;RSS&lt;/span&gt; feed, so if you want to keep track of the progress of this book, simply subscribe to the feed.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=aciKBCk0YkA:LVJcfcYVlJ4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=aciKBCk0YkA:LVJcfcYVlJ4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=aciKBCk0YkA:LVJcfcYVlJ4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=aciKBCk0YkA:LVJcfcYVlJ4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=aciKBCk0YkA:LVJcfcYVlJ4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=aciKBCk0YkA:LVJcfcYVlJ4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=aciKBCk0YkA:LVJcfcYVlJ4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/aciKBCk0YkA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/articles/graphics/webgl-book/webgl</feedburner:origLink></entry>
 
 <entry>
   <title>Platforms and Sandboxes</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/tnRvULN6IwM/platforms-and-sandboxes" />
   <updated>2011-10-12T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/blog/platforms-and-sandboxes</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m in the middle of reading &lt;a href="http://news.ycombinator.com/item?id=3101876"&gt;this HackerNews posting&lt;/a&gt; and I&amp;#8217;m starting to see some parallels between building a tech business on a platform, and creating a sandbox &lt;span class="caps"&gt;RPG&lt;/span&gt; game&lt;sup&gt;1&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Both are based on inverting the work load. Provide a means for other people to do your work for you and they will. The tech business (&lt;span class="caps"&gt;RPG&lt;/span&gt;) will move in a direction your customers (players) want, and you can focus on more important parts of your business (game).&lt;/p&gt;
&lt;p&gt;Interesting.&lt;/p&gt;
&lt;p&gt;&lt;sub&gt;&lt;br /&gt;
1. For those unfamiliar with sandbox &lt;span class="caps"&gt;RPG&lt;/span&gt; games, the person running the game basically presents a complete world with an overall plot, and lets the characters choose their own actions and interact how they will with this world, as opposed to creating individual, fixed story adventures for their players to run through. &lt;br /&gt;
&lt;/sub&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=tnRvULN6IwM:CUmmXw2_ees:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=tnRvULN6IwM:CUmmXw2_ees:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=tnRvULN6IwM:CUmmXw2_ees:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=tnRvULN6IwM:CUmmXw2_ees:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=tnRvULN6IwM:CUmmXw2_ees:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=tnRvULN6IwM:CUmmXw2_ees:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=tnRvULN6IwM:CUmmXw2_ees:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/tnRvULN6IwM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/blog/platforms-and-sandboxes</feedburner:origLink></entry>
 
 <entry>
   <title>A Case for Brevity</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/QtyWh4egXWc/a-case-for-brevity" />
   <updated>2011-10-10T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/blog/a-case-for-brevity</id>
   <content type="html">&lt;p&gt;I have a somewhat keen interest in speed reading, because the world is fascinating and I only have so many years to learn it&amp;#8217;s secrets. One speed reading technique involves reading only the first few sentences of a paragraph, because that&amp;#8217;s where the author makes their point. The rest is just to convince you of it&amp;#8217;s validity. I have seen this true in most places, especially on the internet in blog posts.&lt;/p&gt;
&lt;p&gt;Which is why I find myself wondering why I even write posts, every time I write a post. What am I trying to say? If I have something to say, is it worth an entire post? Do I need to convince people it&amp;#8217;s true?&lt;/p&gt;
&lt;p&gt;I just read a post about perseverence being the key to success, and it was quite long. At least 600 words. I read the first few sentences, then the first sentence of each paragraph and gained no new insights. The author spent their entire post trying to convince me that perseverence is essential for success in anything. Is that something that people need to be convinced of? Are there really people who don&amp;#8217;t already know this? If so, would they likely be reading this article? I don&amp;#8217;t think so.&lt;br /&gt;
The entire article could have been replaced with &amp;#8220;Natural talent is mistakenly assumed to be largely responsible for success; perseverence has more effect on success&amp;#8221;.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s what&amp;#8217;s been holding me back from blogging a lot. I find it difficult to justify padding a simple point out to a &amp;#8220;respectable&amp;#8221; sized post. I think it&amp;#8217;s time I embraced brevity.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=QtyWh4egXWc:TAhy4ki2Jyg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=QtyWh4egXWc:TAhy4ki2Jyg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=QtyWh4egXWc:TAhy4ki2Jyg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=QtyWh4egXWc:TAhy4ki2Jyg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=QtyWh4egXWc:TAhy4ki2Jyg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=QtyWh4egXWc:TAhy4ki2Jyg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=QtyWh4egXWc:TAhy4ki2Jyg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/QtyWh4egXWc" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/blog/a-case-for-brevity</feedburner:origLink></entry>
 
 <entry>
   <title>Literati - Ruby based literate programming library</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/bb6si9t2qsI/literati" />
   <updated>2011-08-15T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/projects/literati</id>
   <content type="html">&lt;h2&gt;Description&lt;/h2&gt;
&lt;p&gt;One of the big issues with development is how fast code&lt;br /&gt;
documentation becomes out of date, when it is written at all.&lt;/p&gt;
&lt;p&gt;While programs are executed by computers, we write them mostly&lt;br /&gt;
for the benefit of other programmers, hence the proliferation of&lt;br /&gt;
high level languages such as Ruby and Python.&lt;/p&gt;
&lt;p&gt;Literate programming is an attempt to solve this problem by &lt;br /&gt;
tightly coupling the code to the documentation, and to help&lt;br /&gt;
programmers write clearer programs for each other first, and for&lt;br /&gt;
computers second.&lt;/p&gt;
&lt;p&gt;Literate programming was pioneered by Donald Knuth, and while there&lt;br /&gt;
are a lot of software packages to tangle/weave literate programming&lt;br /&gt;
files, there&amp;#8217;s a wide variety of syntaxes for writing documents.&lt;/p&gt;
&lt;p&gt;Literati attempts to keep the literate programming syntax as&lt;br /&gt;
close to regular text as possible, so you don&amp;#8217;t have to think&lt;br /&gt;
about how to format your programs and documentation.&lt;/p&gt;
&lt;p&gt;Literati keeps out of your way so you can do what you do best: code.&lt;/p&gt;
&lt;h2&gt;Status&lt;/h2&gt;
&lt;p&gt;This is still very much a rough proof of concept.&lt;/p&gt;
&lt;p&gt;At the moment, the library is contained in one file: literati.rb.&lt;br /&gt;
There are 2 sample programs that you can run through Literati and it&lt;br /&gt;
will produce a Ruby and a Python based calculator.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m in the middle of a rewrite of Literati, in Literati format.&lt;br /&gt;
This can be found in the lib directory, however it&amp;#8217;s not functional.&lt;/p&gt;
&lt;h2&gt;Source&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://github.com/tgittos/literati"&gt;http://github.com/tgittos/literati&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Syntax&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;ve tried to keep the literati syntax as simple as possible. You should be able&lt;br /&gt;
to pick it up by just reading through the two sample programs, however there&lt;br /&gt;
may be some finer points that aren&amp;#8217;t obvious.&lt;/p&gt;
&lt;p&gt;Each code block must have a header, in the form of&lt;br /&gt;
== Identifier ==&lt;br /&gt;
The identifier will uniquely identify that code block, and allow you to reference&lt;br /&gt;
it later in the document.&lt;/p&gt;
&lt;p&gt;You can optionally put more documentation after the header. This documentation&lt;br /&gt;
can be any format you wish.&lt;br /&gt;
After your documentation, you can close the documentation section with&lt;br /&gt;
@api, doc&lt;br /&gt;
This tag tells literati which documentation types this documentation block belongs to.&lt;/p&gt;
&lt;p&gt;Then your source code comes next. You can terminate your source code by starting a new block.&lt;/p&gt;
&lt;p&gt;At the end, you need a program description block, which looks like&lt;br /&gt;
== @filename.rb ==&lt;br /&gt;
The @ in the header marks the name of the file, and below the header block are code section &lt;br /&gt;
references, as defined in the unique identifiers above.&lt;/p&gt;
&lt;p&gt;I know none of this documentation makes any sense, but considering this is still in dev,&lt;br /&gt;
that&amp;#8217;s to be expected.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll rewrite the documentation when I finish refactoring the code.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bb6si9t2qsI:u8qzs8-ac7M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bb6si9t2qsI:u8qzs8-ac7M:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=bb6si9t2qsI:u8qzs8-ac7M:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bb6si9t2qsI:u8qzs8-ac7M:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=bb6si9t2qsI:u8qzs8-ac7M:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bb6si9t2qsI:u8qzs8-ac7M:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=bb6si9t2qsI:u8qzs8-ac7M:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/bb6si9t2qsI" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/literati</feedburner:origLink></entry>
 
 <entry>
   <title>Modeler - 3D modeling in the browser</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/m_-agCJpAdo/modeler" />
   <updated>2011-06-08T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/projects/modeler</id>
   <content type="html">&lt;h2&gt;Goals&lt;/h2&gt;
&lt;p&gt;3D modeling in the browser. No plugins, no programs to install. Just fire up a browser and off you go.&lt;/p&gt;
&lt;h2&gt;Status&lt;/h2&gt;
&lt;p&gt;[07-24-2011] Added in a directional and ambient light to the shader. Next up is point lighting.&lt;/p&gt;
&lt;p&gt;[06-15-2011] Optimizations have been finished and merged into the master branch.&lt;br /&gt;
Next up is implementing a simple lighting model, and then work on setting up the interface to allow geometry to be&lt;br /&gt;
put into a scene.&lt;/p&gt;
&lt;p&gt;[06-08-2011] I&amp;#8217;m putting this demo page up because somebody on Github has asked to see a demo. This project is far&lt;br /&gt;
from nearing a state where you can call it a 3D modeling application. Right now, I have a basic renderer that can take&lt;br /&gt;
a scene made of some primitives and render it to screen. I&amp;#8217;m working on optimizations because there&amp;#8217;s currently a large&lt;br /&gt;
amount of overhead associated with getting objects to the &lt;span class="caps"&gt;GPU&lt;/span&gt; right now.&lt;br /&gt;
My goal is that once I&amp;#8217;ve finished optimizing the core of the renderer, I can start designing a basic interface and&lt;br /&gt;
method of inputing geometry. Then I will perhaps release a stable version of the source.&lt;/p&gt;
&lt;h2&gt;Demo&lt;/h2&gt;
&lt;script type="text/javascript" src="/projects/demos/modeler/app/modeler.min.js"&gt;&lt;/script&gt;&lt;script ty=e"text/javascript"&gt;
  MODELER.BASE = '/projects/demos/modeler/src/'; // reassign the base URL
  function repositionCanvas() {
    var canvas = document.getElementsByTagName('canvas')[0];
    document.getElementById('demo').appendChild(canvas);
  };
&lt;/script&gt;&lt;script type="text/javascript"&gt;
var scene, camera, renderer;
var cube;
var lastTime = 0;
function pageLoaded() {  
    scene = REDBACK.Core.WebGLSceneGraph();
    camera = MODELER.Camera();
    renderer = REDBACK.Core.WebGLRenderer( { scene: scene, camera: camera} );
  
    // first load shaders
  	MODELER.Event.listen(MODELER.EVENTS.FILEMANAGER.LOAD_SUCCESS, fileManagerPreloaded);
  	MODELER.IO.FileManager.preload([
  		MODELER.BASE + 'shaders/webgltexture.vshader',
  		MODELER.BASE + 'shaders/webgltexture.fshader',
  		'/projects/demos/modeler/assets/textures/glass.gif'
  	]);
	
  	function fileManagerPreloaded(){
  		var cube_mat, cube_tex, lighting;
  		cube_tex = REDBACK.Textures.WebGLTexture({
        image: MODELER.IO.FileManager.get('/projects/demos/modeler/assets/textures/glass.gif')
      });
      cube_mat = REDBACK.Materials.WebGLTextureMaterial({
        texture: cube_tex.getTexture()
        ,alpha: 0.5
      });
      cube = MODELER.Primitive.Cube({
        material: cube_mat
  			,z: -10
  			,rotVector: [1, 1, 0]
  			,rotDegrees: 45
      });
      scene.addObject(cube);

      lighting = REDBACK.Lighting.WebGLDirectionalLight({
        direction: [-1.0, 1.0, 1.0],
        colour: [1.0, 1.0, 1.0],
        ambientColour: [0.2, 0.2, 0.2]
      });
      scene.addLight(lighting);

      resizeViewport();
      repositionCanvas();
      render();
  	}  
  };
  function render() {
    var timeNow = new Date().getTime();
    if (lastTime != 0) {
      var elapsed = timeNow - lastTime;
    
      //Do rendering magicks
      cube.rotDegrees += (90 * elapsed) / 1000.0;
    }
    lastTime = timeNow;

    renderer.render();
    requestAnimationFrame(render);
  };
  function resizeViewport(e) {
    renderer.setSize(600, 480);
  };
  window.onload = pageLoaded;
  window.onresize = resizeViewport;
&lt;/script&gt;&lt;div id="demo"&gt;&lt;/div&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;p&gt;For the latest, bleeding edge code, you can go to &lt;a href="http://github.com/tgittos/modeler"&gt;Github&lt;/a&gt; and clone it locally. &lt;br /&gt;
There&amp;#8217;s a terse readme that will describe how to get it up and running on your local computer.&lt;/p&gt;
&lt;p&gt;There are no stable releases right now, as the project is very far from where it needs to be to live up to it&amp;#8217;s goal.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=m_-agCJpAdo:m5n693EFKps:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=m_-agCJpAdo:m5n693EFKps:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=m_-agCJpAdo:m5n693EFKps:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=m_-agCJpAdo:m5n693EFKps:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=m_-agCJpAdo:m5n693EFKps:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=m_-agCJpAdo:m5n693EFKps:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=m_-agCJpAdo:m5n693EFKps:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/m_-agCJpAdo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/modeler</feedburner:origLink></entry>
 
 <entry>
   <title>Now On Jekyll</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/VqfhyiDQRO4/now-on-jekyll" />
   <updated>2011-05-27T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/blog/now-on-jekyll</id>
   <content type="html">&lt;p&gt;I first started my blog in order to help myself learn. I figured that I would be motivated to write, and in order to fully explain things, I would force myself to do research and increase my knowledge on a given topic. So I set up a Wordpress blog, created a very simple theme and got started with it.&lt;/p&gt;
&lt;p&gt;This was all good in theory, but in practice it didn&amp;#8217;t quite work. This really bugged me, because I didn&amp;#8217;t know &lt;em&gt;why&lt;/em&gt; it didn&amp;#8217;t work. I thought about it for a long time, and I think I&amp;#8217;ve figured it out.&lt;/p&gt;
&lt;p&gt;The reason it wasn&amp;#8217;t working is because the way I think and do things is very different from the workflow of Wordpress. Wordpress is a very linear blogging system. Posts are displayed in the order they&amp;#8217;re created, and if you want to do a series of detailed posts in multiple posts, you either need to do them one after the other, or you need to keep them as drafts until they&amp;#8217;re all done.&lt;/p&gt;
&lt;p&gt;I tend to work a little different. I like to do a lot of things at once, and nibble away at posts. I&amp;#8217;ll write a little here and a little there, and generally take my time to produce content. This wasn&amp;#8217;t working for me in Wordpress, and it was actually starting to make me feel bad.&lt;/p&gt;
&lt;p&gt;So, I decided to change to a platform that&amp;#8217;s a little more freestyle. I chose &lt;a href="http://github.com/mojombo/jekyll"&gt;Jekyll&lt;/a&gt; because I decided to integrate my site with Github. Now I don&amp;#8217;t have to worry about logging in to a web based control panel, because everything is handled with public/private key encryptions on Github, and it&amp;#8217;s very easy to deploy to my sever with a post-commit hook that tells my server to do a git pull.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m also writing in textile now, which means that should I produce any content that&amp;#8217;s worth publishing, converting it to TeX then to a &lt;span class="caps"&gt;PDF&lt;/span&gt; or something similar should be equally easy.&lt;/p&gt;
&lt;p&gt;This is probably time for the obligatory &amp;#8220;this is a work in progress&amp;#8221; comment, and to say that things will be in flux for a while, at least until I get settled on a format/workflow that really works for me. I&amp;#8217;ve been working with this for a while now offline, and it seems to be doing the trick, but there are still a few bugs to iron out.&lt;/p&gt;
&lt;p&gt;You can also find all of my old posts still on the website, in my &lt;a href="/archives"&gt;archives&lt;/a&gt; , however I couldn&amp;#8217;t bring across all the comments, so to those of you who commented on my writing, thank you and I&amp;#8217;m sorry.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=VqfhyiDQRO4:AjOTKESdrK4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=VqfhyiDQRO4:AjOTKESdrK4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=VqfhyiDQRO4:AjOTKESdrK4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=VqfhyiDQRO4:AjOTKESdrK4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=VqfhyiDQRO4:AjOTKESdrK4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=VqfhyiDQRO4:AjOTKESdrK4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=VqfhyiDQRO4:AjOTKESdrK4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/VqfhyiDQRO4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/blog/now-on-jekyll</feedburner:origLink></entry>
 
 <entry>
   <title>Pivoting</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/bI_L4b2OA9g/pivoting" />
   <updated>2011-04-20T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/pivoting</id>
   <content type="html">&lt;p&gt;In start-up parlance, to pivot is to change the direction of your attack. Which makes it the perfect description for what I&amp;#8217;m doing.&lt;/p&gt;
&lt;p&gt;When I started this blog, I just wanted to build a name for myself out on the internet. I was aware that potential employers would probably be searching for my name, and I wanted to control the content that they found. I had no overall goals for the blog itself, other than what it would do for me.&lt;/p&gt;
&lt;p&gt;Over time, it evolved into a place for me to share snippets of code and techniques that I&amp;#8217;d found along the way. Each time I did something kind of cool, I&amp;#8217;d write it up and post it online. While I hope that these snippets have helped people, and I know some of them have, I&amp;#8217;ve decided that&amp;#8217;s not really what I want to do with my blog anymore.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve long held the belief that information channels in the human mind are serial. You&amp;#8217;re either consuming information or you&amp;#8217;re producing, but it&amp;#8217;s very hard to do both at the same time. I&amp;#8217;m a consumer, I always have been and I always will be. I&amp;#8217;m fascinated by a whole bunch of different but loosely related things. I don&amp;#8217;t have the time to write regularly while I&amp;#8217;m trying to do all this cool stuff.&lt;/p&gt;
&lt;p&gt;But there&amp;#8217;s the rub: I like to write about what I learn. It helps order my thoughts and creates a reference document for me to refresh my memory from. It&amp;#8217;s secondary to doing cool stuff, and a blog demands to be first choice when it comes to building audiences and producing quality content regularly.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not well suited to the blog format of writing. I&amp;#8217;d prefer to do something awesome, write it up and publish it, and disappear for another 6 months while I do something else awesome. And that&amp;#8217;s exactly what I&amp;#8217;m going to do.&lt;/p&gt;
&lt;p&gt;Lately I&amp;#8217;ve been working deep inside computer graphics, reading and learning and tinkering around in WebGL. I will be doing that for a while, and won&amp;#8217;t be posting here much. But when I do, I&amp;#8217;ll post all about the things I learn.&lt;/p&gt;
&lt;p&gt;Between here and there, I will be migrating off Wordpress and onto Jekyll. These days I carry around a computing device of some kind that I can store files on, so web based access to content is no longer important to me. Jekyll will make the site faster, more secure and easier for me to change and deal with. I have no timeframe for this, and will publish none.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bI_L4b2OA9g:bGRSGsN_Ml8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bI_L4b2OA9g:bGRSGsN_Ml8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=bI_L4b2OA9g:bGRSGsN_Ml8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bI_L4b2OA9g:bGRSGsN_Ml8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=bI_L4b2OA9g:bGRSGsN_Ml8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=bI_L4b2OA9g:bGRSGsN_Ml8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=bI_L4b2OA9g:bGRSGsN_Ml8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/bI_L4b2OA9g" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/pivoting</feedburner:origLink></entry>
 
 <entry>
   <title>The Social Media Revolution</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/g0wD7hNvysw/the-social-media-revolution" />
   <updated>2011-02-15T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/the-social-media-revolution</id>
   <content type="html">&lt;p&gt;I can&amp;#8217;t remember exactly when I first started hearing about the so-called &amp;#8220;Social Media revolution.&amp;#8221; It was right when I was starting to really get into web development. It was easily at least 3 years ago, before Twitter had hit the mainstream like it has now. All I remember is that I didn&amp;#8217;t buy into it.&lt;/p&gt;
&lt;p&gt;I had been a member of a social network called &lt;a href="http://www.deviantart.com"&gt;deviantArt&lt;/a&gt; since 2001, and joined Facebook quickly after it opened it&amp;#8217;s doors to people who weren&amp;#8217;t in school. I had graduated when it reached Australia, and wasn&amp;#8217;t able to create an account. I had interacted with people through an online media for a long time before I heard the phrases &amp;#8220;social network&amp;#8221; and &amp;#8220;social media.&amp;#8221; To me, all this talk from marketers and web designers about leveraging social media, claiming that social media was the way forward, was just that &amp;#8211; talk, nothing but hot air.&lt;/p&gt;
&lt;p&gt;I think today I can say that I understand the social media revolution. All it took was to get involved in creating a social network.&lt;/p&gt;
&lt;p&gt;I have recently changed jobs to an Austin company that is busy building it&amp;#8217;s business social network. Working as close as I am with their social network and learning about how they plan to leverage the community, I can see that I took the wrong end of the stick with regards to social media.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve read a lot of criticism lately about Facebook, with critics saying that Facebook is a hollow way to interact with your friends. They say that it cheapens relationships, and waters down the meaning of &amp;#8216;friend.&amp;#8217; This is the view I&amp;#8217;d had of all social media in the past, and while it may or may not be a valid criticism of Facebook, it&amp;#8217;s certainly not a valid criticism of social media.&lt;/p&gt;
&lt;p&gt;I had a discussion today with a friend about the future of publishing. She&amp;#8217;s in the publishing business, and is violently opposed to e-books and the effects they&amp;#8217;re having on brick and mortar book stores. It was while I was explaining to her my vision of the future that I realised the value of social media. We were musing on the role of publishers in a primarily e-book formatted world where there was almost no hand selling done. She was worried about the authors that weren&amp;#8217;t super stars, and how they would get eyes on their books in a world where you didn&amp;#8217;t have covers to browse, and browsing had a greater friction.&lt;/p&gt;
&lt;p&gt;I explained that it would be social media and social networks that would step in. Websites like &lt;a href="http://www.goodreads.com"&gt;Goodreads&lt;/a&gt; are a good start, where people share their opinions on books and list books they&amp;#8217;ve read and want to read. You&amp;#8217;d build a network of readers that you know, and know the tastes of, and that would provide the data you&amp;#8217;d need to make decisions about new books.&lt;/p&gt;
&lt;p&gt;It was then that I realised the true value of social networks. It&amp;#8217;s a new way for applications to gather real, meaningful data in the most efficient way. By crowd sourcing data, you build a knowledge base in a relevant domain in a very hands off way. By leveraging this data, you can provide very personalised and useful functionality in applications. Rather than make assumptions about your visitors and users, you can obtain hard data and act upon it.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=g0wD7hNvysw:lVimcJ-b-qc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=g0wD7hNvysw:lVimcJ-b-qc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=g0wD7hNvysw:lVimcJ-b-qc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=g0wD7hNvysw:lVimcJ-b-qc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=g0wD7hNvysw:lVimcJ-b-qc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=g0wD7hNvysw:lVimcJ-b-qc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=g0wD7hNvysw:lVimcJ-b-qc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/g0wD7hNvysw" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/the-social-media-revolution</feedburner:origLink></entry>
 
 <entry>
   <title>Safari and Firing Keypress Events with Backspace</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/eM2HAftFjJc/safari-and-firing-keypress-events-with-backspace" />
   <updated>2010-10-05T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/safari-and-firing-keypress-events-with-backspace</id>
   <content type="html">&lt;p&gt;Whilst working on a project for a client that uses a lot of jQuery and &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; &lt;span class="caps"&gt;AJAX&lt;/span&gt;, I found that the &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; AjaxControlToolkit control MaskedEditExtender doesn&amp;#8217;t quite work in Safari. The symptoms of the problem are the backspace and delete keys not working to clear the text in the mask.&lt;/p&gt;
&lt;p&gt;A little too late for my project, there was a fix posted on the &lt;a href="http://ajaxcontroltoolkit.codeplex.com/workitem/17166"&gt;project&amp;#8217;s Codeplex issue tracker&lt;/a&gt; (which I haven&amp;#8217;t verified personally). It involves patching AjaxControlToolkit javascript in source to sniff specifically for Webkit browsers and compiling a new AjaxControlToolkit.dll.&lt;/p&gt;
&lt;p&gt;Instead, I took the extenders out and replaced them with a custom jQuery date mask. I researched a few of the more popular jQuery plugins that do that, but found they didn&amp;#8217;t quite work the way we wanted them to, so I had to roll my own.&lt;/p&gt;
&lt;p&gt;Stupidly, I tested mostly in Firefox, and after a while got it working pretty well. I went to test it in Safari, and it didn&amp;#8217;t work. I feared all the work I had done was for naught. I took a quick look in Safari&amp;#8217;s javascript console and found that Safari wasn&amp;#8217;t firing keypress events for the backspace key, which is what my plugin was listening for.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://unixpapa.com/js/key.html"&gt;As it turns out, this was a known issue with Webkit browsers&lt;/a&gt;. I tested around and figured out that it was &lt;em&gt;just&lt;/em&gt; the keypress event that wasn&amp;#8217;t being fired. The keydown event was being fired fine. So I switched my plugin to listen to the keydown event instead of the keypress event, and that resolved the issue.&lt;/p&gt;
&lt;p&gt;So if you want to support Webkit browsers and you&amp;#8217;re doing key press detection for &amp;#8216;special&amp;#8217; keys, use the keydown event instead of the keypress event. It will save you some frustration.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eM2HAftFjJc:gOrMqxMIC3E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eM2HAftFjJc:gOrMqxMIC3E:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=eM2HAftFjJc:gOrMqxMIC3E:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eM2HAftFjJc:gOrMqxMIC3E:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=eM2HAftFjJc:gOrMqxMIC3E:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eM2HAftFjJc:gOrMqxMIC3E:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=eM2HAftFjJc:gOrMqxMIC3E:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/eM2HAftFjJc" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/safari-and-firing-keypress-events-with-backspace</feedburner:origLink></entry>
 
 <entry>
   <title>Evaluating JSON in Safari</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/1OXpiayjvnI/evaluating-json-in-safari" />
   <updated>2010-08-13T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/evaluating-json-in-safari</id>
   <content type="html">&lt;p&gt;Just a quickie on parsing &lt;span class="caps"&gt;JSON&lt;/span&gt; strings in Safari.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m in the middle of a project developing a timesheet/rostering application, which uses a lot of Javascript. I have a series of web services that interact with jQuery. For reasons beyond the scope of this post, the web service returns a &lt;span class="caps"&gt;JSON&lt;/span&gt; string, which needs to be parsed into a &lt;span class="caps"&gt;JSON&lt;/span&gt; object, and then further processing is done on the object.&lt;/p&gt;
&lt;p&gt;I had a bug where Safari was choking on the &lt;span class="caps"&gt;JSON&lt;/span&gt; string returned by my webservice, yet Firefox and IE were happy parsing it. As it turns out, my &lt;span class="caps"&gt;JSON&lt;/span&gt; string had a Javascript keyword in it; &amp;#8216;break&amp;#8217;.&lt;/p&gt;
&lt;p&gt;Here is my &lt;span class="caps"&gt;JSON&lt;/span&gt; string (well, an example):&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='text'&gt;{employee: 'Joe', worked: true, periods: [{start: '09:00 AM', finish: '17:00 PM'}], break: {paid: true, hours: '1'}}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Safari was choking on the &lt;code&gt;break&lt;/code&gt; in the above &lt;span class="caps"&gt;JSON&lt;/span&gt; string.&lt;/p&gt;
&lt;p&gt;When I wrapped the attribute in single quotes, like so:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='text'&gt;{employee: 'Joe', worked: true, periods: [{start: '09:00 AM', finish: '17:00 PM'}], 'break': {paid: true, hours: '1'}}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;it was happy.&lt;/p&gt;
&lt;p&gt;You can replicate this by using the below code snippet to parse out your &lt;span class="caps"&gt;JSON&lt;/span&gt; string quickly in Safari&amp;#8217;s debug window:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='javascript'&gt;var json = &amp;amp;quot;{employee: 'Joe', worked: true, periods: [{start: '09:00 AM', finish: '17:00 PM'}], break: {paid: true, hours: '1'}}&amp;amp;quot;;
&lt;p&gt;var obj = (new Function(&amp;quot;return &amp;quot; + json))();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;which should fail. If you add the single quotes around &lt;code&gt;break&lt;/code&gt; though, it should work just fine.&lt;/p&gt;
&lt;p&gt;This also fails for other Javascript keywords:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='javascript'&gt;(new Function(&amp;amp;quot;return &amp;amp;quot; + &amp;amp;quot;{if: true}&amp;amp;quot;))();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;fails. If you wrap &lt;code&gt;if&lt;/code&gt; in single quotes, it works.&lt;/p&gt;
&lt;p&gt;I think the take away lesson is to always wrap your object attributes in a &lt;span class="caps"&gt;JSON&lt;/span&gt; string in single quotes, otherwise Safari will choke on it.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=1OXpiayjvnI:IytZpUciEhI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=1OXpiayjvnI:IytZpUciEhI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=1OXpiayjvnI:IytZpUciEhI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=1OXpiayjvnI:IytZpUciEhI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=1OXpiayjvnI:IytZpUciEhI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=1OXpiayjvnI:IytZpUciEhI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=1OXpiayjvnI:IytZpUciEhI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/1OXpiayjvnI" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/evaluating-json-in-safari</feedburner:origLink></entry>
 
 <entry>
   <title>Autostart a VPN in Windows XP/Vista</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/w-dnQ2Bcano/autostart-vpn-in-windows-vista" />
   <updated>2010-03-10T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/blog/autostart-vpn-in-windows-vista</id>
   <content type="html">&lt;h1&gt;Autostart a &lt;span class="caps"&gt;VPN&lt;/span&gt; in Windows XP/Vista&lt;/h1&gt;
&lt;p&gt;Just a quick one today, and it&amp;#8217;s exactly what it says on the box.&lt;/p&gt;
&lt;p&gt;I was unreasonably inconvenienced by the need to manually dial into my works &lt;span class="caps"&gt;VPN&lt;/span&gt; everytime I start my computer up. For some reason it really rubbed me the wrong way.&lt;/p&gt;
&lt;p&gt;A few days ago, I finally decided to solve this niggling problem once and for all. Here are the steps you&amp;#8217;ll need, assuming you already have the Windows &lt;span class="caps"&gt;VPN&lt;/span&gt; client configured for a &lt;span class="caps"&gt;VPN&lt;/span&gt;:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Save your authentication details in the connection&lt;/li&gt;
	&lt;li&gt;Set the &lt;span class="caps"&gt;VPN&lt;/span&gt; connection to &lt;em&gt;not&lt;/em&gt; prompt for user details (Start &amp;#8594; Connect To &amp;#8594; right click on your &lt;span class="caps"&gt;VPN&lt;/span&gt; &amp;#8594; Properties &amp;#8594; Options &amp;#8594; uncheck &amp;#8220;Prompt for name and password&amp;#8221;)&lt;/li&gt;
	&lt;li&gt;Create a .bat file somewhere safe, and put in it the following: &lt;code&gt;rasdial "Name of your VPN Connection"&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Create a shortcut to this .bar file&lt;/li&gt;
	&lt;li&gt;Put this shortcut into your startup folder&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, the next time reboot, your &lt;span class="caps"&gt;VPN&lt;/span&gt; should start as soon as you get an internet connection.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=w-dnQ2Bcano:tKMcrCNVmqg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=w-dnQ2Bcano:tKMcrCNVmqg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=w-dnQ2Bcano:tKMcrCNVmqg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=w-dnQ2Bcano:tKMcrCNVmqg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=w-dnQ2Bcano:tKMcrCNVmqg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=w-dnQ2Bcano:tKMcrCNVmqg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=w-dnQ2Bcano:tKMcrCNVmqg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/w-dnQ2Bcano" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/blog/autostart-vpn-in-windows-vista</feedburner:origLink></entry>
 
 <entry>
   <title>ProxyBotLib</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/xf5slrLme2U/starcraft-ai" />
   <updated>2010-02-19T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/starcraft-ai</id>
   <content type="html">&lt;p&gt;A library for connecting a .&lt;span class="caps"&gt;NET&lt;/span&gt; based bot to the Starcraft Brood War &lt;span class="caps"&gt;API&lt;/span&gt; &lt;a href="http://code.google.com/p/bwapi/"&gt;http://code.google.com/p/bwapi/&lt;/a&gt;. Contains source for the &lt;span class="caps"&gt;BWAPI&lt;/span&gt; socket communication dll and the .&lt;span class="caps"&gt;NET&lt;/span&gt; proxy bot.&lt;/p&gt;
&lt;p&gt;Available from &lt;a href="http://github.com/tgittos/ProxyBotLib"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Created for use with the &lt;span class="caps"&gt;EIS&lt;/span&gt; Starcraft AI competition &lt;a href="http://eis.ucsc.edu/StarCraftAICompetition"&gt;http://eis.ucsc.edu/StarCraftAICompetition&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Based on &lt;a href="http://breakablec.redirectme.net/svn/repos/trunk/StarProxyBot_net/"&gt;http://breakablec.redirectme.net/svn/repos/trunk/StarProxyBot_net/&lt;/a&gt; which is based on &lt;a href="http://eis.ucsc.edu/StarCraftRemote"&gt;http://eis.ucsc.edu/StarCraftRemote&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Getting Started&lt;/h1&gt;
&lt;p&gt;This library is intended to aid an external, .&lt;span class="caps"&gt;NET&lt;/span&gt; based AI bot to connect to the &lt;span class="caps"&gt;BWAPI&lt;/span&gt; socket. To get started, create a new console application which will be the base for your AI agent. Add the ProxyBotLib project to the solution, and add to the console application a reference to ProxyBotLib. There is a sample agent in ProxyBotLib.Tests that you should move to the console application. Create an instance of the agent, and create an instance of the ProxyBot, passing the agent to the constructor of the ProxyBot.&lt;/p&gt;
&lt;h1&gt;Example&lt;/h1&gt;
&lt;pre&gt;
&lt;code&gt;
[STAThread]
public static void Main(System.String[] args)
{
    StarCraftAgent agent = new StarCraftAgent();
    ProxyBot proxyBot = new ProxyBot(agent);

    try
    {
        proxyBot.start();
    }
    catch (SocketException e)
    {
        Console.Error.WriteLine(e.StackTrace);
        System.Environment.Exit(0);
    }
    catch (System.Exception e)
    {
        Console.Error.WriteLine(e.StackTrace)
    }
}
&lt;/code&gt;
&lt;/pre&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=xf5slrLme2U:22wxeHSjjwM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=xf5slrLme2U:22wxeHSjjwM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=xf5slrLme2U:22wxeHSjjwM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=xf5slrLme2U:22wxeHSjjwM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=xf5slrLme2U:22wxeHSjjwM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=xf5slrLme2U:22wxeHSjjwM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=xf5slrLme2U:22wxeHSjjwM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/xf5slrLme2U" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/starcraft-ai</feedburner:origLink></entry>
 
 <entry>
   <title>OpenGLBase</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/S1JX-u8DYYE/openglbase" />
   <updated>2010-02-17T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/projects/openglbase</id>
   <content type="html">&lt;p&gt;Please see the project on Github for more details:&lt;br /&gt;
&lt;a href="http://github.com/tgittos/openglbase"&gt;On Github&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=S1JX-u8DYYE:Q8irwqCe4Uo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=S1JX-u8DYYE:Q8irwqCe4Uo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=S1JX-u8DYYE:Q8irwqCe4Uo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=S1JX-u8DYYE:Q8irwqCe4Uo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=S1JX-u8DYYE:Q8irwqCe4Uo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=S1JX-u8DYYE:Q8irwqCe4Uo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=S1JX-u8DYYE:Q8irwqCe4Uo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/S1JX-u8DYYE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/projects/openglbase</feedburner:origLink></entry>
 
 <entry>
   <title>ASP.NET GridView with an ObjectDataSource</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/hTjJvNNzNEw/asp-net-gridview-with-an-objectdatasource" />
   <updated>2009-10-26T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/asp-net-gridview-with-an-objectdatasource</id>
   <content type="html">&lt;p&gt;Just a quick tip:&lt;/p&gt;
&lt;p&gt;I got the following exception today:&lt;/p&gt;
&lt;pre&gt;If a data source does not return ICollection and cannot return the total row count, 
it cannot be used by the GridView to implement server-side paging.&lt;/pre&gt;
&lt;p&gt;If you&amp;#8217;re trying to return an IEnumerable from your select method, try changing it to a List or an array. That should clear the problem right up.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=hTjJvNNzNEw:DU7ero6ceL4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=hTjJvNNzNEw:DU7ero6ceL4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=hTjJvNNzNEw:DU7ero6ceL4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=hTjJvNNzNEw:DU7ero6ceL4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=hTjJvNNzNEw:DU7ero6ceL4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=hTjJvNNzNEw:DU7ero6ceL4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=hTjJvNNzNEw:DU7ero6ceL4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/hTjJvNNzNEw" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/asp-net-gridview-with-an-objectdatasource</feedburner:origLink></entry>
 
 <entry>
   <title>Going Dark</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/uC2jaYp5_DM/going-dark" />
   <updated>2009-10-13T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/going-dark</id>
   <content type="html">&lt;p&gt;Nearly 12 months on from the start of my blog (the first post went up at the end of November 2008), I&amp;#8217;m finding less and less time to do the quality kind of writing I have set out to do. I feel that, as I change, so too does my website need to change.&lt;/p&gt;
&lt;p&gt;As much as this site is currently a programming blog, it&amp;#8217;s also my electronic representation. The website shares my name, and is representative of me. There&amp;#8217;s more to me than just programming. For a while I&amp;#8217;ve tried blogging or writing about non-programming related topics on another domain, however I don&amp;#8217;t feel this is fair to myself.&lt;/p&gt;
&lt;p&gt;I guess the best way to describe myself is an &lt;a href="http://en.wikipedia.org/wiki/Polymath"&gt;aspiring polymath&lt;/a&gt;. I have an interest in a broad range of topics, notably programming/computer science, mathematics and art. This website doesn&amp;#8217;t really represent that. I can&amp;#8217;t maintain multiple websites to separate various areas of my life &amp;#8211; I&amp;#8217;m a single person with multiple facets, and I should have a single website, with multiple facets.&lt;/p&gt;
&lt;p&gt;Additionally, I find myself with less and less time to devote to this kind of writing, as it slowly makes it&amp;#8217;s way down to the bottom of my priority list. Currently I&amp;#8217;m trying to rekindle my math education by going back to basics, learn Punjabi so I can impress the fiance&amp;#8217;s parents, do several programming projects at once and get back into doing art regularly, and writing is a very far last.&lt;/p&gt;
&lt;p&gt;So, all that lead up to say that I&amp;#8217;m going dark, and will be overhauling the site sometime in the future. I&amp;#8217;m going to change the format of the site so that it more accurately represents me as a whole, is better organised and has a nice format that allows me to post quick, smaller posts that can be filtered out when subscribing to &lt;span class="caps"&gt;RSS&lt;/span&gt; feed. I may or may not stick with Wordpress &amp;#8211; I think I&amp;#8217;ll probably start hacking away at &lt;a href="http://www.enkiblog.com/"&gt;Enki&lt;/a&gt; and do some funky stuff with wildcard subdomains or something.&lt;/p&gt;
&lt;p&gt;All older posts will remain, as a few of my posts are rather popular (by more than 50% compared to the rest of the site) and I suspect they&amp;#8217;re really helping people out.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=uC2jaYp5_DM:MGlkgTBoMQ4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=uC2jaYp5_DM:MGlkgTBoMQ4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=uC2jaYp5_DM:MGlkgTBoMQ4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=uC2jaYp5_DM:MGlkgTBoMQ4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=uC2jaYp5_DM:MGlkgTBoMQ4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=uC2jaYp5_DM:MGlkgTBoMQ4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=uC2jaYp5_DM:MGlkgTBoMQ4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/uC2jaYp5_DM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/going-dark</feedburner:origLink></entry>
 
 <entry>
   <title>Mario AI Competition 2009 - Getting Started</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/nu66pRFR88g/mario-ai-competition-2009-getting-started" />
   <updated>2009-08-25T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/mario-ai-competition-2009-getting-started</id>
   <content type="html">&lt;p&gt;Programming is fun. That&amp;#8217;s why I decided it would be a good career for me. I love solving puzzles, and I love the concept of making computers, these mysterious boxes of my childhood, do things. However, when you finally get to working as a professional programmer, the types of projects you get to work on are often not as interesting as you&amp;#8217;d like. This is why I am interested in AI. AI presents new and unique challenges, and techniques of approaching these challenges. I said in a previous post that AI was more commonplace than you&amp;#8217;d think, but didn&amp;#8217;t really follow it up with suggestions of where you can work on AI related programs.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve recently stumbled on an interesting AI competition (before it got big with the video &amp;#8211; I&amp;#8217;ve been writing this post for about a month), based off of an open source Java project called Inifine Mario, called &lt;a href="http://julian.togelius.com/mariocompetition2009/"&gt;Mario AI Competition 2009&lt;/a&gt;. The competition is to create an AI agent that can navigate randomly generated Mario levels, pitting each agent against each other. The first round of this competition has already closed, however there is another round that closes September 3.&lt;/p&gt;
&lt;p&gt;I won&amp;#8217;t be attending the conferences nor will I be submitting agents to the competition. I will however work on a few agents, as this is probably the most fun application of AI that I&amp;#8217;ve seen in a while, and it&amp;#8217;s a small enough environment to enable me to get very familiar with it very quickly, and hence get into making solutions very quickly.&lt;/p&gt;
&lt;p&gt;On the surface, this seems a trivial, niche problem. An agent that can navigate a video game level doesn&amp;#8217;t really have a lot of diverse applications. However, it&amp;#8217;s a great way to begin practicing some fundamental concepts of AI. The parameters of the competition don&amp;#8217;t limit the techniques you can use to create the agent. In the video below, &lt;a href="http://www.doc.ic.ac.uk/~rb1006/projects:marioai"&gt;Robin Baumgarten&lt;/a&gt; is using A* path finding techniques.&lt;/p&gt;
&lt;p&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/DlkMs4ZHHr8&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;feature=player_embedded&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/DlkMs4ZHHr8&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;feature=player_embedded&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;However, A* is just the start, and is a fairly basic approach (though it works pretty well by the demos), and there are many more options, including machine learning and neural networks. Unfortunately, I won&amp;#8217;t be covering any of that yet. The goal of this post is to get myself, and anyone else interested, up to speed on the environment, and the basics of creating an agent. I will be creating a very simple reactive agent that has no planning, and is quite flawed. However, you should be able to walk away with a firm grasp of how the environment works and what tools you have at your disposal.&lt;/p&gt;
&lt;p&gt;Before I go on, a disclaimer is necessary: I haven&amp;#8217;t worked with Java since my university days, so about 6 years or so. I will post some code, and that code will probably suck. You have been warned.&lt;/p&gt;
&lt;h3&gt;The Game Environment&lt;/h3&gt;
&lt;p&gt;The details on the code available from the competition website are fairly vague, so I&amp;#8217;m posting this to perhaps help some people who are interested in getting into it, and also for my reference to help while working on it. Firstly, obviously, you&amp;#8217;re going to have to download the code available on the competition website. The code is relatively stable at this point, however it was constantly being updated with fixes for bugs posted on the &lt;a href="http://groups.google.com/group/mariocompetition"&gt;Google Group&lt;/a&gt; for the competition. These changes would be posted on the group, so I&amp;#8217;d check it regularly, or grab it from &lt;a href="http://code.google.com/p/marioai/"&gt;Google Code&lt;/a&gt; with svn, and just update your repo regularly. Once you&amp;#8217;ve downloaded it, open it in your &lt;span class="caps"&gt;IDE&lt;/span&gt;/editor of choice, and roll up your sleeves.&lt;/p&gt;
&lt;p&gt;Firstly, I&amp;#8217;m going to reference classes by their fully qualified class names; ie: ch.idsia.scenarios.Play, which references Play.java located in the src/ch/idsia/scenarios folder. This way you can play along at home.&lt;/p&gt;
&lt;p&gt;According to the online documentation, you can fire up a run by typing&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='text'&gt;java ch.idsia.scenarios.Play&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;from within the &amp;#8220;classes&amp;#8221; directory. This will start a copy of the Infinite Mario game with a human player. To start with a pre written agent, type&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='text'&gt;java ch.idsia.scenarios.Play ch.idsia.ai.agents.ai.ForwardJumpingAgent&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;to start with an agent that will run forward and jump as soon as it can.&lt;/p&gt;
&lt;p&gt;The ch.idsia.scenarios.Play class is a simple class that sets up the agent, whether it&amp;#8217;s human controlled or automated, and then it sets some play environment variables and runs the application. If an argument is supplied, it will attempt to instantiate an instance of the class and pass it through to the play environment.&lt;/p&gt;
&lt;p&gt;I won&amp;#8217;t be covering the the details of the simulation code, as it&amp;#8217;s all pretty logically separated and you don&amp;#8217;t really need to know how to do that. Information is passed through to the agent through an implementation of the interface ch.idsia.mario.environments.Environment. This argument to the &lt;code&gt;getAction&lt;/code&gt; function provides the agent with a serialised view of the terrain and the location of enemies, along with information about Mario. Basically, any information you can get by looking at the scene.&lt;/p&gt;
&lt;p&gt;This information is provided in the form of a byte matrix, through several functions. &lt;code&gt;observation.getLevelSceneObservation()&lt;/code&gt; will return a matrix with details of the terrain. It will also tell you what the type of the terrain is, such as a pipe or a one way platform. This detail is found in &lt;code&gt;ch.idsia.mario.engine.LevelScene&lt;/code&gt;. You can see the number codes for the different types of terrain. It&amp;#8217;s broken down into gaps, hard borders, half borders and flower pots.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;observation.getEnemiesObservation()&lt;/code&gt; is very similar to &lt;code&gt;observation.getLevelSceneObservation()&lt;/code&gt;, except it addresses enemy locations. Again, you&amp;#8217;ll also get the type of the enemy from the matrix in the form of an integer code, which you can find in &lt;code&gt;ch.idsia.mario.engine.sprites.Sprite&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve written a debugging function that will output both the enemy and terrain matricies to give you a code view of what&amp;#8217;s going on. It&amp;#8217;s interesting and enlightening to watch the code view of the simulation next to the simulation itself, and it will help us write code to fit our design. The function is as follows:&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='java'&gt;byte[][] levelState = observation.getLevelSceneObservation();
byte[][] enemyState = observation.getEnemiesObservation();&lt;/p&gt;
&lt;p&gt;//Debug information&lt;br /&gt;
for (int y = 0; y &amp;lt; 22; y++)&lt;br /&gt;
{&lt;br /&gt;
    for (int x = 0; x &amp;lt; 22; x++)&lt;br /&gt;
    {&lt;br /&gt;
        //Check for enemies first&lt;br /&gt;
        if (enemyState[y][x] &amp;gt; 0)&lt;br /&gt;
        {&lt;br /&gt;
            String enemyValue = Integer.toString(enemyState[y][x]);&lt;br /&gt;
            int padding = 3 &amp;#8211; enemyValue.length();&lt;br /&gt;
            if (enemyState[y][x] == 1)&lt;br /&gt;
                System.out.print(&amp;quot;mmm&amp;quot;);&lt;br /&gt;
            else if (padding == 2)&lt;br /&gt;
                System.out.print(&amp;quot; &amp;quot; + enemyValue + &amp;quot; &amp;quot;);&lt;br /&gt;
            else if (padding == 1)&lt;br /&gt;
                System.out.print(&amp;quot; &amp;quot; + enemyValue);&lt;br /&gt;
            else&lt;br /&gt;
                System.out.print(enemyValue);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            //Check for terrain next&lt;br /&gt;
            String terrainValue = Integer.toString(levelState[y][x]);&lt;br /&gt;
            int padding = 3 &amp;#8211; terrainValue.length();&lt;br /&gt;
            if (padding == 2)&lt;br /&gt;
                System.out.print(&amp;quot; &amp;quot; + terrainValue + &amp;quot; &amp;quot;);&lt;br /&gt;
            else if (padding == 1)&lt;br /&gt;
                System.out.print(&amp;quot; &amp;quot; + terrainValue);&lt;br /&gt;
            else&lt;br /&gt;
                System.out.print(terrainValue);&lt;br /&gt;
        }&lt;br /&gt;
        System.out.print(&amp;quot;|&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    System.out.print(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
System.out.print(&amp;quot;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;-\n&amp;quot;);&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I put the above code into a function in the agent itself, and called the function from the &lt;code&gt;getAction&lt;/code&gt; function of the agent, purely because I know this is going to get called once per tick. You can put it wherever you want to put it.&lt;/p&gt;
&lt;h3&gt;Creating a Dumb Agent&lt;/h3&gt;
&lt;p&gt;As I mentioned at the start of this post, I&amp;#8217;m just going to start with creating a very simple, dumb agent that will attempt to traverse the level, and even then not get it right all the time for reasons I will cover. On the surface, Mario&amp;#8217;s tasks for navigating a stage without enemies is pretty straightforward. All he needs to do is to get himself around the level and jump over pits.&lt;/p&gt;
&lt;p&gt;However, sometimes Mario can find himself falling into a gap, or over-jumping his mark and jumping into a hole. So basically, we need to check if there&amp;#8217;s something in Mario&amp;#8217;s path that needs to be jumped over, or if there&amp;#8217;s a gap that we need to jump over. But, we can&amp;#8217;t just jump &amp;#8211; we also need to check if jumping is going to put is into a gap and kill Mario, and if Mario runs off of where ever he is, he might fall into a hole.&lt;/p&gt;
&lt;p&gt;This would be fairly straight forward if we had a robust method of predicting where Mario&amp;#8217;s jumps will take him, but unfortunately we don&amp;#8217;t officially get this information. &lt;br /&gt;
There is a movement algorithm in &lt;code&gt;ch.idsia.mario.engine.sprites.Mario&lt;/code&gt;, which starts at the &lt;code&gt;move&lt;/code&gt; method, however, not only is this not in the spirit of the competition, but more importantly, it&amp;#8217;s very hard to figure out, for me at least. I&amp;#8217;ve not been able to reliably modify the movement code to act as a predictor of Mario&amp;#8217;s path if you plug-in how long to hold each key for.&lt;/p&gt;
&lt;p&gt;Hence, at this stage, we&amp;#8217;ll just be making Mario go right and try and jump over obstacles. Seems fairly simple.&lt;/p&gt;
&lt;p&gt;You&amp;#8217;ll see in the provided agents that the function &lt;code&gt;getAction&lt;/code&gt; is the heart of the agent, and an instance of the Environment interface discussed before. This function is the work horse of your agent, as it will tell the simulation what the agent is going to do.&lt;/p&gt;
&lt;p&gt;Although the &lt;code&gt;observation.getLevelSceneObservation()&lt;/code&gt; and &lt;code&gt;observation.getEnemiesObservation()&lt;/code&gt; methods return the full view of the level, all the features are jumbled together. Later on, we&amp;#8217;ll need to know what&amp;#8217;s a cannon and what&amp;#8217;s a pipe, and what&amp;#8217;s raised ground, and maybe even what&amp;#8217;s a block we can punch. We&amp;#8217;ll need to know this because cannons shoot Bullet Bills and enemy flowers live in pipes, and these can appear at any time, and if Mario is near by, he&amp;#8217;s going to get hurt.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve created the following function to categorize the environment into pipes, cannons and pits:&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='java'&gt;private Boolean[] pits;
private Vector cannons;
private Vector pipes;
private void processTerrain(byte[][] state)
{
    //Init features
    pits = new boolean[22];
    cannons = new Vector();
    pipes = new Vector();&lt;/p&gt;
//Init pits
for (int i = 0; i &amp;lt; 22; i++)
{
pits[i] = true;
}
for (int y = 21; y &amp;gt;= 0; y&amp;#8212;)
{
for (int x = 0; x &amp;lt; 22; x++)
{
//Look for gaps
pits[x] = pits[x] &amp;amp;&amp;amp; state[y][x] == 0;
//Look for cannons and pipes
if (state[y][x] == 20)
{
boolean pipeFound = false;
//Check if x,y is in pipes
int pipeLength = pipes.size();
for (int pi = 0; pi &amp;lt; pipeLength; pi++)
{
int[] coords = (int[])pipes.elementAt(pi);
if (coords != null &amp;amp;&amp;amp; coords&lt;sup class="footnote" id="fnr0"&gt;&lt;a href="#fn0"&gt;0&lt;/a&gt;&lt;/sup&gt; == x &amp;amp;&amp;amp; coords&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; == y)
{
//Pipe found, skip it
pipeFound = true;
}
}
if (!pipeFound)
{
//Peek ahead to determine if it&amp;#8217;s a pipe or a cannon
if(x &amp;lt; 21 &amp;amp;&amp;amp; state[y][x + 1] == 20)
{
//It&amp;#8217;s a pipe, add it and the next one to the pipe array
pipes.add(new int[]{x + 1, y});
}
else
{
//It&amp;#8217;s a cannon
cannons.add(new int[]{x, y});
}
}
}
}
}
&lt;p&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The three variables are defined as private members of the agent, and calling this function will populate them with tile locations in the case of pipes and cannons, and tile columns in the case of pits. You don&amp;#8217;t have to do this with such a simple agent &amp;#8211; you can simply use similar techniques to parse over the whole level state.&lt;/p&gt;
&lt;p&gt;I use this information to determine how far away obstacles are. At first I was going to make the distance between obstacles affect the jumping distance and height, however without an accurate way to determine where jumps are going to land, this can actually cause more harm than good. So I ignore it, and just use a fairly blunt approach.&lt;/p&gt;
&lt;p&gt;Firstly, another helper function:&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='java'&gt;private int setDeltaForObstacles(Vector tiles)
{
    int length = tiles.size();
    int buffer = 0;
    int localDeltaX = 0;
    //Loop through every tile
    for (int counter = 0; counter &amp;amp;lt; length; counter++)
    {
        //Get coords of tile
        int[] coords = (int[])tiles.elementAt(counter);
        //Calculate the delta, then check to see if it's good enough
        localDeltaX = coords[0] - 11;
        if (action[Mario.KEY_RIGHT] &amp;amp;amp;&amp;amp;amp; coords[0] &amp;amp;gt; 11)
        {
            //If the tile is after mario, and we're heading right, delta is good
            break;
        }
        else if (action[Mario.KEY_LEFT] &amp;amp;amp;&amp;amp;amp; coords[0] &amp;amp;lt; 11)
        {
            //If the tile is before mario and we're heading left, add to buffer
            if (coords[0] &amp;amp;gt; buffer)
                buffer = coords[0];
        }
        else if (action[Mario.KEY_LEFT])
        {
            //If the tile is after mario, but we're heading left, get the last tile loc from the buffer
            localDeltaX = buffer - 11;
            break;
        }
    }
    return localDeltaX;
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This function takes a Vector and will return the closes tile to Mario, depending on his direction. It&amp;#8217;s a very coarse way to determine the closes obstacle to Mario. Bear in mind that it doesn&amp;#8217;t recognise when obstacles are put close together, thus doesn&amp;#8217;t optimise Mario&amp;#8217;s jumping.&lt;/p&gt;
&lt;p&gt;The goal of the agent is to jump over the closest obstacle. That&amp;#8217;s it. Considering our obstacles are now in three different datastructures (cannons in one, pipes in another, and pits and raised terrain in the original byte array), we need to store the delta (distance between Mario and the closes obstacle) and update it only when we&amp;#8217;ve found a smaller delta. Also, I want to keep the delta of any pits separate, as I&amp;#8217;m going to have different rules for pits than other obstacles (because pits are the only thing that can kill Mario at this stage).&lt;/p&gt;
&lt;p&gt;To this end, I create two integer variables at the top of the &lt;code&gt;getAction&lt;/code&gt; method. They are intitialized to 11 because this is where Mario is:&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='java'&gt;int deltaX = 11;
int deltaJump = 11;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Here is the code to extract the delta of the nearest obstacle, and the delta of the nearest pit. Note that &lt;code&gt;levelState&lt;/code&gt; is the results from a call to &lt;code&gt;observation.getLevelSceneObservation&lt;/code&gt;:&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='java'&gt;//Analyse pipes       
int pipeDelta = setDeltaForObstacles(pipes);  
if (pipeDelta &amp;amp;lt; deltaX &amp;amp;amp;&amp;amp;amp; pipeDelta &amp;amp;gt; 0)
    deltaX = pipeDelta;
//Analyse cannons
int cannonDelta = setDeltaForObstacles(cannons);
if (cannonDelta &amp;amp;lt; deltaX &amp;amp;amp;&amp;amp;amp; cannonDelta &amp;amp;gt; 0)
    deltaX = cannonDelta;&lt;/p&gt;
&lt;p&gt;//Analyse the gaps&lt;br /&gt;
boolean gap = false;&lt;br /&gt;
for(int y = 0; y &amp;lt; 22; y++)&lt;br /&gt;
{&lt;br /&gt;
    if (pits[y])&lt;br /&gt;
    {&lt;br /&gt;
        if (action[Mario.KEY_RIGHT] &amp;amp;&amp;amp; y &amp;gt; 11)&lt;br /&gt;
        {&lt;br /&gt;
            int localDelta = y &amp;#8211; 11;&lt;br /&gt;
            if (localDelta &amp;lt; deltaJump)&lt;br /&gt;
                deltaJump = localDelta;&lt;br /&gt;
        }&lt;br /&gt;
        else if (action[Mario.KEY_LEFT] &amp;amp;&amp;amp; y &amp;lt; 11)&lt;br /&gt;
        {&lt;br /&gt;
            int localDelta = 11 &amp;#8211; y;&lt;br /&gt;
            if (localDelta &amp;lt; deltaJump)&lt;br /&gt;
                deltaJump = localDelta;&lt;br /&gt;
        }&lt;br /&gt;
        gap = true;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;/p&gt;
&lt;p&gt;//Analyse ground above Mario&lt;br /&gt;
boolean raisedGround = false;&lt;br /&gt;
if (action[Mario.KEY_RIGHT])&lt;br /&gt;
{&lt;br /&gt;
    for (int x = 12; x &amp;lt; 22; x++)&lt;br /&gt;
    {&lt;br /&gt;
        for (int y = 12; y &amp;gt;= 0; y&amp;#8212;)&lt;br /&gt;
        {&lt;br /&gt;
            if (levelState[y][x] == -10)&lt;br /&gt;
            {&lt;br /&gt;
                int localDelta = x &amp;#8211; 11;&lt;br /&gt;
                if (localDelta &amp;lt; deltaX)&lt;br /&gt;
                    deltaX = localDelta;&lt;br /&gt;
                raisedGround = true;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        if (raisedGround)&lt;br /&gt;
            break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Once we have the deltas, we can use this information to decide what to do. I mentioned above treating obstacle deltas different from jump deltas. This is an attempt to make Mario take smaller jumps when he can see a pit is after an obstacle. This is controlled by two instance members that keep track of jump height and jump length, called &lt;code&gt;jumpHeight&lt;/code&gt; and &lt;code&gt;jumpLength&lt;/code&gt; respectively. This is very hit and miss. Notice that Mario does not respond to anything more than 4 tiles away, and tiles that are behind him. This is to prevent him from going jump crazy:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='java'&gt;jumpHeight = 7;
&lt;p&gt;jumpLength = 14;// * (deltaX / 11);&lt;br /&gt;
if (((pipes.size() &amp;gt; 0 || cannons.size() &amp;gt; 0 || raisedGround) &amp;amp;&amp;amp; deltaX &amp;gt;= 0 &amp;amp;&amp;amp; deltaX &amp;lt; 5))&lt;br /&gt;
{&lt;br /&gt;
    if (observation.mayMarioJump() &amp;amp;&amp;amp; !action[Mario.KEY_JUMP])&lt;br /&gt;
        action[Mario.KEY_JUMP] = true;&lt;br /&gt;
}&lt;/p&gt;
&lt;p&gt;//If mario is jumping, there must be an obstacle in the way&lt;br /&gt;
if (action[Mario.KEY_JUMP])&lt;br /&gt;
{&lt;br /&gt;
    if (gap &amp;amp;&amp;amp; deltaJump &amp;gt;= 3)&lt;br /&gt;
    {&lt;br /&gt;
        jumpHeight = 7;&lt;br /&gt;
        jumpLength = 1;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
//No obstacles, but there is a gap&lt;br /&gt;
else if (gap &amp;amp;&amp;amp; deltaJump &amp;gt;= 0 &amp;amp;&amp;amp; deltaJump &amp;lt;= 3)&lt;br /&gt;
{&lt;br /&gt;
    if (observation.mayMarioJump() &amp;amp;&amp;amp; !action[Mario.KEY_JUMP])&lt;br /&gt;
        action[Mario.KEY_JUMP] = true;&lt;br /&gt;
}&lt;br /&gt;
maintainJump();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Finally, the &lt;code&gt;maintainJump&lt;/code&gt; method is to ensure we&amp;#8217;re holding down the jump key for the optimal amount of time. It is also coded to provide rudimentary control over jump height and length, however this isn&amp;#8217;t being taken advantage of.&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='java'&gt;private void maintainJump()
&lt;p&gt;{&lt;br /&gt;
    if(action[Mario.KEY_JUMP] &amp;amp;&amp;amp; (jumpCount &amp;gt; jumpHeight))&lt;br /&gt;
    {&lt;br /&gt;
        action[Mario.KEY_JUMP] = false;&lt;br /&gt;
        jumpCount = 0;&lt;br /&gt;
    }&lt;br /&gt;
    // otherwise you&amp;#8217;re in the middle of jump, increment jumpCount&lt;br /&gt;
    else if (action[Mario.KEY_JUMP])&lt;br /&gt;
    {&lt;br /&gt;
        jumpCount++;&lt;br /&gt;
    }&lt;br /&gt;
    if (jumping)&lt;br /&gt;
    {&lt;br /&gt;
        if (action[Mario.KEY_RIGHT] &amp;amp;&amp;amp; (rightCount &amp;gt; jumpLength))&lt;br /&gt;
        {&lt;br /&gt;
            action[Mario.KEY_RIGHT] = false;&lt;br /&gt;
            rightCount = 0;&lt;br /&gt;
        }&lt;br /&gt;
        else if (action[Mario.KEY_RIGHT])&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The complete agent is at the bottom of this post for you to download and include in your project. Simply put it in the path &lt;code&gt;src/timgittos&lt;/code&gt;, configure the &lt;code&gt;ch.idsia.scenarios.Play&lt;/code&gt; class to have no enemies, with &lt;code&gt;options.setPauseWorld(true)&lt;/code&gt;, and run any level you want (passable result with difficulty 3). Then build the project and run it with &lt;code&gt;java ch.idsia.scenarios.Play timgittos.BlogAgent&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As you will observe, the agent will make Mario go towards the right as fast as possible, jumping over obstacles as it meets them.  For the most part, it works well enough. However, there are quite a few fatal flaws, and I will explain why it fails in this way.&lt;/p&gt;
&lt;p&gt;Most obviously, the agent frequently falls down gaps. It doesn&amp;#8217;t fall down all gaps &amp;#8211; which would indicate that it&amp;#8217;s not a failure in the gap detection, but rather something else. In fact, what&amp;#8217;s going on is that the gaps that Mario tends to fall down are those that enter his field of consideration (4 tiles ahead of him) while he&amp;#8217;s in the air. The agent makes no effort to check whether it&amp;#8217;s jump will land Mario in a pit (since it can&amp;#8217;t predict where Mario will land), and my previous efforts at trying to make the agent force Mario to the left when it detects he&amp;#8217;s going to go down a pit have failed.&lt;/p&gt;
&lt;p&gt;Mario will also fall down pits if there are multiple pits in a row. Again, this is because the agent doesn&amp;#8217;t exert much control over the size and length of Mario&amp;#8217;s jumps ,and so can&amp;#8217;t pin point that it wants to land in the middle of the two pits, so it tends to overshoot the jump and fall down the second pit.&lt;/p&gt;
&lt;p&gt;Most annoyingly, the agent will sometimes get stuck. If it reaches an obstacle, such as a cannon or a bit of wall or a pipe and jumps at the wrong angle, it will enter a weird wall jump loop, where it jumps, gets stuck on the obstacle, jumps off, jumps again, and gets stuck again. This will loop until there is no time. This is a side effect of the environment allowing wall jumps, which is cool when you can get the agent to make Mario jump out of a pit he&amp;#8217;s falling into, but annoying when he gets stuck.&lt;/p&gt;
&lt;p&gt;In any case, this agent is far from complete, and just serves to demonstrate how the simulation environment works, and how to interact with it. Once you&amp;#8217;re clear how to work with the simulation, you can concentrate on building a useful agent, either by starting from scratch (like you would if you were going to use a machine learning approach), or by building on top of this base (for a determinate approach like A*).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Download: &lt;a href='/files/archives/BlogAgent.java'&gt;Mario AI Blog agent (.java)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=nu66pRFR88g:K4npEBgHpw8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=nu66pRFR88g:K4npEBgHpw8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=nu66pRFR88g:K4npEBgHpw8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=nu66pRFR88g:K4npEBgHpw8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=nu66pRFR88g:K4npEBgHpw8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=nu66pRFR88g:K4npEBgHpw8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=nu66pRFR88g:K4npEBgHpw8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/nu66pRFR88g" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/mario-ai-competition-2009-getting-started</feedburner:origLink></entry>
 
 <entry>
   <title>Configuring webHttpBinding When Using WCF with JQuery</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/oeRvQXMnYPo/configuring-webhttpbinding-when-using-wcf-with-jquery" />
   <updated>2009-06-24T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/configuring-webhttpbinding-when-using-wcf-with-jquery</id>
   <content type="html">&lt;p&gt;Firstly, a disclaimer: I don&amp;#8217;t have a lot of experience working with &lt;span class="caps"&gt;AJAX&lt;/span&gt; enabled &lt;span class="caps"&gt;WCF&lt;/span&gt; services, and from reading some of &lt;a href="http://www.west-wind.com/presentations/jQuery/default.aspx"&gt;Rick Strahl&amp;#8217;s posts on using JQuery with &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt;&lt;/a&gt;, I&amp;#8217;m doing things in a really hackish and terrible manner. Hopefully my mistakes won&amp;#8217;t impact the usefulness of this short tip.&lt;/p&gt;
&lt;p&gt;When working with JQuery and &lt;span class="caps"&gt;AJAX&lt;/span&gt; enabled &lt;span class="caps"&gt;WCF&lt;/span&gt; services, I recently encountered the following error, through Firebug and Fiddler:&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
The maximum string content length quota (8192) has been exceeded while reading &lt;span class="caps"&gt;XML&lt;/span&gt; data. &lt;br /&gt;
This quota may be increased by changing the &lt;br /&gt;
MaxStringContentLength property on the XmlDictionaryReaderQuotas &lt;br /&gt;
object used when creating the &lt;span class="caps"&gt;XML&lt;/span&gt; reader.&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;This is caused by &lt;span class="caps"&gt;WCF&lt;/span&gt; webHttpBinding default having fairly draconion limitations on &lt;span class="caps"&gt;XML&lt;/span&gt; message length and depth. &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/6ad1bf1c-e340-44ae-8ba5-91428d6e78a7"&gt;This thread on &lt;span class="caps"&gt;MSDN&lt;/span&gt;&lt;/a&gt; helped diagnose the problem, however it didn&amp;#8217;t do much to help me solve my particular problem. Ultimately, I stumbled upon the solution quite accidentally.&lt;/p&gt;
&lt;p&gt;Firstly, as per the &lt;span class="caps"&gt;MSDN&lt;/span&gt; thread, you need to add the custom binding configuration underneath the &lt;system.serviceModel&gt; configuration section:&lt;br /&gt;
[xml]&lt;br /&gt;
&lt;system.serviceModel&gt;&lt;br /&gt;
  &lt;bindings&gt;&lt;br /&gt;
    &lt;webHttpBinding&gt;&lt;br /&gt;
      &lt;binding name="bindingConfiguration"&gt;&lt;br /&gt;
        &lt;readerQuotas maxDepth="32" maxStringContentLength="2048000" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /&gt;&lt;/p&gt;
&lt;/binding&gt;
&lt;/webHttpBinding&gt;
&lt;/bindings&gt;
..
&lt;/system.serviceModel&gt;
&lt;p&gt;[/xml]&lt;/p&gt;
&lt;p&gt;At first I thought this was a custom binding, and tried to replace the service endpoint binding to the custom binding defined above, however this was causing an &amp;#8220;System.ServiceModel.ServiceActivationException&amp;#8221; exception.&lt;/p&gt;
&lt;p&gt;The above binding declaration is actually a configuration for the webHttpBinding. As such, you need to add the BindingConfiguration property onto your service endpoint, along side your binding declaration. This is as follows:&lt;br /&gt;
[xml]&lt;br /&gt;
&lt;service behaviorConfiguration="Your.Service.Behavior"
      name="Your.Service.Name"&gt;&lt;br /&gt;
    &lt;endpoint address="" behaviorConfiguration="Your.Behavior.Configuration"
     binding="webHttpBinding" bindingConfiguration="bindingConfiguration" contract="Your.Service.Contract" /&gt;&lt;/p&gt;
&lt;/service&gt;
&lt;p&gt;[/xml]&lt;/p&gt;
&lt;p&gt;This will allow you to send larger messages to your &lt;span class="caps"&gt;WCF&lt;/span&gt; services via &lt;span class="caps"&gt;AJAX&lt;/span&gt;, and get on with creating applications.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oeRvQXMnYPo:smkRfrLRY1A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oeRvQXMnYPo:smkRfrLRY1A:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=oeRvQXMnYPo:smkRfrLRY1A:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oeRvQXMnYPo:smkRfrLRY1A:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=oeRvQXMnYPo:smkRfrLRY1A:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oeRvQXMnYPo:smkRfrLRY1A:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=oeRvQXMnYPo:smkRfrLRY1A:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/oeRvQXMnYPo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/configuring-webhttpbinding-when-using-wcf-with-jquery</feedburner:origLink></entry>
 
 <entry>
   <title>Going Camping with CouchDB On OS X Tiger</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/IW2LS713WgM/going-camping-with-couchdb-on-os-x-tiger" />
   <updated>2009-06-12T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/going-camping-with-couchdb-on-os-x-tiger</id>
   <content type="html">&lt;p&gt;With &lt;a href="http://www.engadget.com/2009/06/08/apple-shipping-snow-leopard-in-september-29-upgrade/"&gt;Snow Leopard being released at the end of September this year&lt;/a&gt;, Tiger is definitely starting to show it&amp;#8217;s age. I&amp;#8217;ve been putting off upgrading to Leopard for quite some time, not being able to justify the down time associated with upgrading an OS. This has had an unpleasant side effect of not being able to do things quite as easily as I want, and finding information is hard.&lt;/p&gt;
&lt;p&gt;Due to the &lt;a href="http://www.timgittos.com/a-cms-in-ruby-and-why-i-stopped"&gt;recommendations in the comments of my Ruby &lt;span class="caps"&gt;CMS&lt;/span&gt; article&lt;/a&gt;, I have decided to start playing with the &lt;a href="http://camping.rubyforge.org/files/README.html"&gt;Camping Ruby microframework&lt;/a&gt; backed by &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt;. Getting Camping up and running was easy enough, and I managed to get some trivial functionality going. Camping uses SQLite for it&amp;#8217;s database, which is fine if I wanted to massage my data into a relational form. However, I have models with optional attributes, and rather than making nullable database types, I want to leverage CouchDB&amp;#8217;s schema-less, RESTful document storage. Each persisted object in my application will be available on a unique url, so CouchDB is a nice fit for what I want to do.&lt;/p&gt;
&lt;h3&gt;The Great Installation&lt;/h3&gt;
&lt;p&gt;I found this &lt;a href="http://knuthellan.wordpress.com/2009/03/08/camping-with-couchdb/"&gt;great article&lt;/a&gt; about getting Camping talking to CouchDB, and it seemed easy enough, so I decided to try it. Since I already had Camping working, all I needed was to get CouchDB installed on my Macbook. As much as I&amp;#8217;m not scared of compiling applications from source, I&amp;#8217;ve had issues in the past with OS X and compiling, so I decide to find a simple package or disk image to install. I found &lt;a href="http://janl.github.com/couchdbx/"&gt;CouchDBX&lt;/a&gt;, however checking the requirements showed that it supports Leopard only.&lt;/p&gt;
&lt;p&gt;With a little more research, I found out I had to use &lt;a href="http://www.macports.org/"&gt;Macports&lt;/a&gt; to install CouchDB. Macports relies on XCode Tools which come available on the DVDs that came with OS X. If you haven&amp;#8217;t previously installed XCode Tools, then you should install them before you install Macports. Something that is buried in a &lt;a href="http://trac.macports.org/ticket/18282"&gt;support ticket&lt;/a&gt;, however, is that Macports targets XCode tools 2.5. My XCode tools was something like 2.4.8. While I did manage to get Macports installed, the installation for CouchDB fails when it tries to build tk. If you, like me, have an older XCode Tools than 2.5, you&amp;#8217;ll need to download 2.5, which you can find &lt;a href="http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?bundleID=19907"&gt;deep inside the Apple website&lt;/a&gt;. This does require an Apple Developer Connection account to get, so if you don&amp;#8217;t have one, you&amp;#8217;ll need to create one.&lt;/p&gt;
&lt;p&gt;Installing CouchDB is as simple as issuing&lt;br /&gt;
[bash]&lt;br /&gt;
sudo port install couchdb&lt;br /&gt;
[/bash]&lt;br /&gt;
and Macports will take care of the rest. CouchDB lists it&amp;#8217;s dependencies as Spidermonkey, Erlang and a few others, however each of those has dependencies, and each of those dependencies has dependencies, and it ends up taking quite a long time and downloading a fair few packages. The upside is that if you didn&amp;#8217;t have Erlang previously installed, you do now. Erlang is something I&amp;#8217;ve been wanting to take a look at.&lt;/p&gt;
&lt;h3&gt;Start The Server Before You Leap&lt;/h3&gt;
&lt;p&gt;While the article I linked to above about getting Camping and CouchDB talking is good, it&amp;#8217;s not exactly the most verbose explanation especially if you haven&amp;#8217;t read the documentation for CouchDB and prefer to just dive in. For those who are still a little unsure like I was about how exactly to do this, I&amp;#8217;ll outline my approach below.&lt;/p&gt;
&lt;p&gt;Before you get started writing any code at all, you need to start your CouchDB server. This is something that escaped me for the longest time, and when I finally twigged, it gave me a bit of grief. To start CouchDB, issue the following command:&lt;br /&gt;
[bash]&lt;br /&gt;
sudo couchdb&lt;br /&gt;
[/bash]&lt;br /&gt;
If you try this without escalating privilege, it will return an error &amp;quot;{&amp;quot;init terminating in do_boot&amp;quot;,,[{couch_server_sup,start_server,1},{erl_eval,do_apply,5},{erl_eval,exprs,5}, {init,start_it,1},{init,start_em,1}]}}&amp;quot;, which searching for will bring you to the &lt;a href="http://wiki.apache.org/couchdb/Error_messages"&gt;CouchDB&lt;/a&gt; wiki page for error messages. This page will tell you the problem is an unavailable port. For me, at least, this is not true. CouchDB runs on port 5984 which as far as I know is not used for any system services or other software. The reason I was getting this error was that I wasn&amp;#8217;t running it with enough privilege.&lt;/p&gt;
&lt;p&gt;Once you get CouchDB started, you&amp;#8217;ll notice it blocks the terminal. I don&amp;#8217;t like to have too many windows open at once, so I&amp;#8217;d prefer to have it run as a background process. Fortunately CouchDB will let you do that with a command line switch option, along with changing the location of the pid file. I&amp;#8217;ll leave figuring out how you want to start it up to you.&lt;/p&gt;
&lt;p&gt;Once you have CouchDB started, you&amp;#8217;ll have access to a web-based administration panel called Futon. Futon is available to you at &lt;code&gt;http://localhost:5984/_utils/&lt;/code&gt;, assuming you&amp;#8217;re running CouchDB on your local host. The Futon utility will allow you to create databases and insert documents in preparation to test your connectivity with Camping.&lt;/p&gt;
&lt;h3&gt;Camping Time&lt;/h3&gt;
&lt;p&gt;There were two Ruby gems I had considered when deciding how to connect Ruby to CouchDB. I should point out that due to the RESTful nature of CouchDB, you strictly don&amp;#8217;t need any Ruby gems and could roll your own fairly easily, if you wanted to. I didn&amp;#8217;t want that level of control, personally. The two gems I considered were &lt;a href="http://github.com/jchris/couchrest/tree/master"&gt;CouchRest&lt;/a&gt; and &lt;a href="http://github.com/paulcarey/relaxdb/tree/master"&gt;RelaxDB&lt;/a&gt;. CouchRest is a simple Ruby wrapper around the CouchDB &lt;span class="caps"&gt;REST&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt;, whereas RelaxDB is more abstracted, bringing ActiveRecord-like functionality to CouchDB. While before I would have chosen RelaxDB, I&amp;#8217;m intentionally trying to work a little closer to the raw APIs here, so I chose CouchRest.&lt;/p&gt;
&lt;p&gt;You can install CouchRest through RubyGems:&lt;br /&gt;
[bash]&lt;br /&gt;
sudo gem install couchrest&lt;br /&gt;
[/bash]&lt;br /&gt;
however I found that the gem version wouldn&amp;#8217;t work and kept throwing errors when I started my Camping application. To overcome this, I just cloned it from the GitHun repository and placed it in my Camping app directory and referenced it that way.&lt;/p&gt;
&lt;p&gt;The first thing to do would be to create a normal Camping sample application, if you haven&amp;#8217;t done already. For the purposes of this post, I&amp;#8217;m going to use the &amp;#8220;&amp;#8221;http://camping.rubyforge.org/files/&lt;span class="caps"&gt;README&lt;/span&gt;.html&amp;quot;&amp;gt;skeletal Camping blog&lt;/a&gt;&amp;quot; application used in the documentation, and edit that to work with CouchDB. I figure this will give everyone a relatively common base from which to start. Import CouchRest just below where the application imports Camping:&lt;br /&gt;
[ruby]&lt;br /&gt;
require &amp;#8216;camping&amp;#8217;&lt;br /&gt;
require &amp;#8216;couchrest&amp;#8217; # or &amp;#8216;couchrest/couchrest&amp;#8217; or similar if you&amp;#8217;ve cloned from Github&lt;br /&gt;
[/ruby]&lt;/p&gt;
&lt;p&gt;Given that the purpose of this article is to demonstrate connecting to CouchDB, and not the design of a framework around it, we can safely ignore defining a model for now, and rely on CouchDB as our model. So if you&amp;#8217;re following along from the example application, you can safely delete the classes from Blog::Models module. We&amp;#8217;re not going to delete the whole module, because of the &lt;code&gt;create&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;The Camping &lt;a href="http://camping.rubyforge.org/classes/Camping.html"&gt;create&lt;/a&gt; method that is run when the server starts up your Camping app. From the documentation, &amp;#8220;This is a good place to check for database tables and create those tables to save users of your application from needing to manually set them up.&amp;#8221; Instead, we&amp;#8217;re going to use this method to set up CouchRest in our application:&lt;br /&gt;
[ruby]&lt;br /&gt;
module Blog::Models&lt;br /&gt;
  def Blog.create&lt;br /&gt;
    db_url = &amp;#8216;http://localhost:5984/&amp;#8217;&lt;br /&gt;
    storage = CouchRest.database(&amp;#8220;#{db_url}blog&amp;#8221;)&lt;br /&gt;
    Blog::Controllers::Index.set_storage(storage)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
[/ruby]&lt;/p&gt;
&lt;p&gt;Next, because we&amp;#8217;re now calling a new method on the controller class, we need to modify that. Change the Blog::Controllers::Index class to the following:&lt;br /&gt;
[ruby]&lt;br /&gt;
module Blog::Controllers&lt;br /&gt;
  class Index &amp;lt; R &amp;#8216;/(\w+)&amp;#8217;&lt;br /&gt;
    def Index.set_storage(storage)&lt;br /&gt;
      &lt;code&gt;@storage = storage
    end
    def get(id)
      @post = @&lt;/code&gt;storage.get(&amp;#8216;posts/&amp;#8217; + id)&lt;br /&gt;
      render :index&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
[/ruby]&lt;br /&gt;
What I&amp;#8217;ve done here is given the controller class a static reference to my CouchDB database (from the &lt;code&gt;create&lt;/code&gt; method). Then the controller was changed to respond to a regex, which is passed into the get method. We use the id passed in to retrieve a document from CouchDB, which we assign as an instance variable.&lt;/p&gt;
&lt;p&gt;Lastly, we need to modify the Index function view to pull data from the CouchDB database:&lt;br /&gt;
[ruby]&lt;br /&gt;
def index&lt;br /&gt;
  h1 @post[:title]&lt;br /&gt;
end&lt;br /&gt;
[/ruby]&lt;br /&gt;
This will output the title of the test document created at the start of the article.&lt;/p&gt;
&lt;p&gt;If you haven&amp;#8217;t already, start up Futon and create a database for the purposes of this demo. Call the database &amp;#8220;blog&amp;#8221;, and fill it with a test document with the id of &amp;#8220;posts/test&amp;#8221;, and at least a &amp;#8220;title&amp;#8221; property with the value &amp;#8220;Test Post&amp;#8221;, and any other properties you wish.&lt;/p&gt;
&lt;p&gt;Start the Camping application with &lt;code&gt;camping blog.rb&lt;/code&gt;, and point a browser to &lt;code&gt;http://localhost:3301/test&lt;/code&gt;, and you should see &amp;#8220;Test Post&amp;#8221; in a header tag, rendered out to the browser, which means that Camping has successfully communicated with CouchDB.&lt;/p&gt;
&lt;p&gt;I didn&amp;#8217;t cover putting data into CouchDB, however you would do it in a similar vein, writing a &lt;code&gt;post&lt;/code&gt; method inside your routes to create data and save it to CouchDB. From here, personally, I&amp;#8217;m going to create some wrapper classes for requests and models and build up something which is a little DRYer, however as far as a demo, this is good enough.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=IW2LS713WgM:AEUple91GDo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=IW2LS713WgM:AEUple91GDo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=IW2LS713WgM:AEUple91GDo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=IW2LS713WgM:AEUple91GDo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=IW2LS713WgM:AEUple91GDo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=IW2LS713WgM:AEUple91GDo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=IW2LS713WgM:AEUple91GDo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/IW2LS713WgM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/going-camping-with-couchdb-on-os-x-tiger</feedburner:origLink></entry>
 
 <entry>
   <title>My Best Guesses About Wolfram Alpha</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/BfW6WvJ95_w/my-best-guesses-about-wolfram-alpha" />
   <updated>2009-05-19T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/my-best-guesses-about-wolfram-alpha</id>
   <content type="html">&lt;p&gt;Following the &amp;#8220;soft launch&amp;#8221; of Wolfram Alpha a few days ago, I&amp;#8217;ve been wondering exactly how Wolfram Alpha works. From the description of all the hype leading up to it, it seemed like a question answering application that is specialized in answering questions, as opposed to say Google, which is more into finding and presenting data, leaving the interpretation to humans. Now that it&amp;#8217;s here, we can have a play around and see what it can do.&lt;/p&gt;
&lt;p&gt;Firstly, I tried to &lt;a href="http://www.wolframalpha.com/input/?i=how+does+wolfram+alpha+work" title="How does Wolfram Alpha work - Wolfram Alpha"&gt;ask Wolfram Alpha how it worked&lt;/a&gt;, and it just gave me a puzzled look. So I can only guess, and guess I shall.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://www.wolframalpha.com/about.html"&gt;Wolfram Alpha website lays it all out on the table&lt;/a&gt;, with regards to what it&amp;#8217;s all about. Wolfram Alpha&amp;#8217;s goal &amp;#8220;is to accept completely free-form input, and to serve as a knowledge engine&amp;#8221; to answer search queries entered. From the very limited playing I&amp;#8217;ve done, it seems pretty cool.&lt;/p&gt;
&lt;p&gt;Following my move from Perth to Texas, I typed in &amp;#8220;&amp;#8221;http://www.wolframalpha.com/input/?i=austin+to+perth&amp;quot;&amp;gt;Austin to Perth&lt;/a&gt;&amp;quot; into Wolfram Alpha just to see what it told me. I got back map, with a line drawn between the cities. I got the distance in miles between the two and the flight time. I got a side by side comparison of the local times, populations and approximate elevations.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.google.com/search?q=austin+to+perth"&gt;Google however, delivered me what I was actually looking for, sort of.&lt;/a&gt; Maybe that&amp;#8217;s just a difference in expectations and thinking.&lt;sup&gt;1&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s clear that Wolfram Alpha is pretty cool, and will do some awesome things with the data before it returns it back to you, but it doesn&amp;#8217;t really help me figure out how it works. My thoughts are that Wolfram Alpha combines a large database of indexed knowledge in the form of a knowledge base and a powerful logical language, the language being Stephen Wolfram&amp;#8217;s own &lt;a href="http://en.wikipedia.org/wiki/Mathematica" title="Mathematica on Wikipedia"&gt;Mathematica&lt;/a&gt;, naturally. As he describes it, Wolfram Alpha is the &amp;#8220;killer-app&amp;#8221; for Mathematica.&lt;/p&gt;
&lt;p&gt;First, lets discuss the vast store of data available to Wolfram Alpha, most likely in the form of a knowledge base. A knowledge base is an information representation scheme designed to allow information to be operated on using logic. Information is stored in &amp;#8220;sentences&amp;#8221; in a knowledge representation language. The knowledge base allows logical agents, in this case the Wolfram Alpha application, to receive queries, and then search and analyse the knowledge base, performing logical inferences and information compounding, then collating it and returning the results. The logical agent does all the heavy lifting, but the very structure of the knowledge base helps the agent.&lt;/p&gt;
&lt;p&gt;The heart of the logical agent is it&amp;#8217;s knowledge representation language. It allows the agent to &amp;#8220;reason&amp;#8221; through sentences and make inferences in order to derive new facts. Proposition logic and First-order logic are both knowledge representation languages. Knowledge representation languages use syntax and semantics to define knowledge, where syntax outlines the structure of a language, and the semantics are the meaning.&lt;/p&gt;
&lt;p&gt;Logic is a very mathematical concept, and mathematics can be seen as a kind of logic that operates on numbers. Mathematics has a syntax, that defines the infix notation of logical operators on operands, and the semantics are what those operators do. 1 + 1 = 2 is an example of a complex logical language, where the syntax defines that the + operator acts on each 1, and the = operator defines the result of the previous operation. The semantics define that the value of 1 + 1 is 2.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.wolframalpha.com/2009/05/01/the-secret-behind-the-computational-engine-in-wolframalpha/" title="The Secret Behind the Computational Engine in Wolfram Alpha"&gt;Mathematica, the heart of Wolfram Alpha&lt;/a&gt;, is a computational language, according to it&amp;#8217;s Wikipedia page. It&amp;#8217;s built on top of the &lt;a href="http://en.wikipedia.org/wiki/Symbolic_Manipulation_Program" title="Symbolic Manipulation Program - Wikipedia"&gt;Symbolic Manipulation Program&lt;/a&gt;, designed by both Chris A. Cole and Stephen Wolfram. The Symbolic Manipulation Program is a &amp;#8220;computer algebra system&amp;#8221;, which facilitates symbolic computation,  allowing computers to operate on symbols and manipulate expressions instead of operating on their values, which sounds a heck of a lot like something that could be used to create a logic that can operate on a knowledge base.&lt;/p&gt;
&lt;p&gt;Going back to logical agents and knowledge bases, there are a number of ways logical agents can extract and infer information from knowledge bases. The topic of knowledge based logical agents is a pretty vast one, and I couldn&amp;#8217;t possibly explain it completely in a single post, even if I knew more than just a fraction of it, which I don&amp;#8217;t. But I can summarize what I do understand, and how it applies to Wolfram Alpha.&lt;/p&gt;
&lt;p&gt;As referred to often in the post so far, inference or &lt;em&gt;entailment&lt;/em&gt; plays a large part of how a logical agent can extract &amp;#8220;new&amp;#8221; information from a knowledge base. &lt;a href="http://en.wikipedia.org/wiki/Inference" title="Inference - Wikipedia"&gt;Inference&lt;/a&gt; is deeply rooted in formal logic, and techniques have been developed to allow automated software processes to apply it to a knowledge base.&lt;/p&gt;
&lt;p&gt;Logical entailment is the idea that a sentence &amp;#8220;logically follows&amp;#8221; another sentence. If a given sentence &lt;strong&gt;a&lt;/strong&gt; is true, and the truth of sentence &lt;strong&gt;b&lt;/strong&gt; depends on the truth of &lt;strong&gt;a&lt;/strong&gt;, then &lt;strong&gt;b&lt;/strong&gt; must be true, and also that if &lt;strong&gt;b&lt;/strong&gt; is true, then logically &lt;strong&gt;a&lt;/strong&gt; must also be true. This is useful if the knowledge base doesn&amp;#8217;t contain the fact that one of &lt;strong&gt;a&lt;/strong&gt; or &lt;strong&gt;b&lt;/strong&gt; is true, but it does contain definition that the truth of &lt;strong&gt;b&lt;/strong&gt; depends on the truth of &lt;strong&gt;a&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The knowledge base is designed to be a model of reality, and holds sentences about the world intended to describe it to a level of detail. Sentences can be as atomic as facts, such as &amp;#8220;the sky is blue&amp;#8221;, or can be logical sentences such as &amp;#8220;if the sun is in the sky, it is not night&amp;#8221;, which of course has exceptions (such as in certain seasons in the polar regions), which also need to be modeled in the knowledge base.&lt;/p&gt;
&lt;p&gt;This is relevant because, with a finite model represented by the knowledge base, there are a finite number of entailment and inferences that can be made on the model, which means that a logical agent such as Wolfram Alpha can reduce the world to a finite search space, and can run a search over this space looking for information that follows on from the set of facts in the knowledge base.&lt;/p&gt;
&lt;p&gt;Search techniques for searching the knowledge base are similar as search techniques in other AI based problems, such as constraint satisfaction problems and touring problems. These searching algorithms include backtracking and local search methods, such as hill climbing.&lt;/p&gt;
&lt;p&gt;When searching this knowledge base, the logical agent needs to abide by a series of rules, known as inference rules, in order to guarantee the the knowledge it entails and infers is valid.&lt;/p&gt;
&lt;p&gt;Firstly, the logical agent needs to be aware of the equivalence of two logical sentences. If two sentences are both true under the same model, such as the Wolfram Alpha knowledge base, then they are logically equivalent, and can be used to format facts in a different way to aid inference.&lt;/p&gt;
&lt;p&gt;Secondly, the logical agent needs to be aware of the concept of validity. A sentence is valid if it is true in every model, which essentially means it&amp;#8217;s a tautology and is always true. These tautologies are useful because they aid in validating inferences, where &lt;strong&gt;a&lt;/strong&gt; infers &lt;strong&gt;b&lt;/strong&gt; if a implies &lt;strong&gt;b&lt;/strong&gt; is a tautology, where implication is such that &lt;strong&gt;b&lt;/strong&gt; is true if and only if &lt;strong&gt;a&lt;/strong&gt; is true. This can get a little confusing, and if you can, I&amp;#8217;d suggest you read Chapter 7 in &lt;a href="http://www.amazon.com/gp/product/0137903952?ie=UTF8&amp;tag=gebloftigi-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0137903952"&gt;AI:&lt;span class="caps"&gt;AMA&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;
.&lt;/p&gt;
&lt;p&gt;Thirdly, it needs to ensure the sentence is satisfiable, which means it&amp;#8217;s true in at least one model, which is basically just searching for inferences and determining that, for a given search space state, the inference being suggested is true.&lt;/p&gt;
&lt;p&gt;The logical agent and inference/entailment from a knowledge base can be observed in Wolfram Alpha with a fairly simple query: &amp;#8220;&amp;#8221;http://www.wolframalpha.com/input/?i=red+%2B+yellow&amp;quot;&amp;gt;red + yellow&lt;/a&gt;&amp;quot;. In this query, the logical agent would probably hit the knowledge base and tell it that both red and yellow are true, meaning that we want to find information about those. It would then search for all sentences that are entailed or logical structures that mention the fact red or yellow, such as a sentence &amp;#8220;orange is a mix of red and yellow&amp;#8221;. It would then tell the knowledge base that this fact had been entailed, and tell it that orange is true. Then, when it finds the sentence &amp;#8220;blue is complementary to orange&amp;#8221;, it can add that to the record set. Obviously there will be other sentences in the knowledge base, and the agent will have to use a filtering algorithm to determine which sentences and facts are relevant to the query, otherwise it might return results that the user is not interested in.&lt;/p&gt;
&lt;p&gt;To successfully parse the search query, it would also need a measure of natural language processing, so that it can convert a human-readable query into a machine readable query. This, combined with a large, extensive knowledge base, a fast logical language such as Mathematica and AI techniques for inference and entailment of knowledge mean that Wolfram Alpha can answer a wide range of questions that a simple indexed and categorised search engine couldn&amp;#8217;t.&lt;/p&gt;
&lt;p&gt;However that&amp;#8217;s just my best guess. And keep in mind who I am: I&amp;#8217;m just a young web developer with an interest in AI. I don&amp;#8217;t actively participate in AI research, and I have no formal training. My guesses and musings are probably widely off the mark, and if anyone has any other ideas or corrections, clarifications or discussions, I&amp;#8217;d love to hear them in the comments.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;sub&gt;&lt;br /&gt;
&lt;ol&gt;&lt;br /&gt;
&lt;li&gt;If you mistype a search query into Wolfram Alpha, curiously it won&amp;#8217;t suggest a correction. Considering how relatively easy this task is (&lt;a href="http://en.wikipedia.org/wiki/Levenshtein_distance"&gt;just use it&amp;#8217;s Levenshtein Distance&lt;/a&gt;), I find it odd that it doesn&amp;#8217;t support this.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;/sub&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BfW6WvJ95_w:HCkUo25H6VI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BfW6WvJ95_w:HCkUo25H6VI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=BfW6WvJ95_w:HCkUo25H6VI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BfW6WvJ95_w:HCkUo25H6VI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=BfW6WvJ95_w:HCkUo25H6VI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BfW6WvJ95_w:HCkUo25H6VI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=BfW6WvJ95_w:HCkUo25H6VI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/BfW6WvJ95_w" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/my-best-guesses-about-wolfram-alpha</feedburner:origLink></entry>
 
 <entry>
   <title>Now Appearing In Austin, Texas</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/t76yTWW8BvY/now-appearing-in-austin-texas" />
   <updated>2009-04-26T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/now-appearing-in-austin-texas</id>
   <content type="html">&lt;p&gt;This blog has gone dark over the last two or so weeks, but for a very good reason. On the 21&lt;sup&gt;st&lt;/sup&gt; of April, I flew from Perth, Western Australia to Austin, Texas, where I will be staying for the next 6 months. For those not acquainted with the trip, it&amp;#8217;s half a world away at over 13,000km, for a total flying time of 29 hours not including layovers (for my trip, anyway).&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been spending the last week settling down here in Austin, and the week before that preparing for the trip. I&amp;#8217;m still suffering from some jet lag, and catching up on the last 8 months with my girlfriend, who I hadn&amp;#8217;t seen since August 2008. I haven&amp;#8217;t had the time nor the concentration required to write a blog post, and I haven&amp;#8217;t touched my Google Reader account, which I can see has over 1,600 unread articles.&lt;/p&gt;
&lt;p&gt;However, I do have some interesting posts coming up. I&amp;#8217;m planning a response to an AI article that was linked to me in a comment, a more in depth look at the importance of searching by solving the 8-Queens problems in Python using some different search techniques, and a look at creating some graceful degradation control adapters for &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; server controls that don&amp;#8217;t work without Javascript.&lt;/p&gt;
&lt;p&gt;So, don&amp;#8217;t unsubscribe from my feed in your readers, the blog isn&amp;#8217;t abandoned, life has just taken priority over it. When things settle down, I&amp;#8217;ll start writing articles again.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=t76yTWW8BvY:AmA6MlxBZmM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=t76yTWW8BvY:AmA6MlxBZmM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=t76yTWW8BvY:AmA6MlxBZmM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=t76yTWW8BvY:AmA6MlxBZmM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=t76yTWW8BvY:AmA6MlxBZmM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=t76yTWW8BvY:AmA6MlxBZmM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=t76yTWW8BvY:AmA6MlxBZmM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/t76yTWW8BvY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/now-appearing-in-austin-texas</feedburner:origLink></entry>
 
 <entry>
   <title>Where Do We Draw The Line On Complexity?</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/HDiCJ1Lhzgo/where-do-we-draw-the-line-on-complexity" />
   <updated>2009-04-15T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/where-do-we-draw-the-line-on-complexity</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve got a few posts planned about AI and &lt;span class="caps"&gt;HCI&lt;/span&gt;, however these require a lot of time to research and write code for, time that I don&amp;#8217;t have given I&amp;#8217;m flying to the US on the 21&lt;sup&gt;st&lt;/sup&gt; of April. So I apologise to people who saw my last AI article on Hacker News and Reddit and subscribed to my feed expecting more of the same. There will be more, I promise. I just need more time. For now, just some musings.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been thinking a lot lately about solving problems. I read a number of programming aggregators and startup blogs, and the term &amp;#8220;solve a problem&amp;#8221; keeps nagging at me. To be successful, at programming and business, you need to solve a problem. I&amp;#8217;d love to eventually run a development company, but I don&amp;#8217;t know what problem to solve. So, I consider the problem my current employer is solving.&lt;/p&gt;
&lt;p&gt;I currently work for a web development company that is doing fairly well. We have a suite of products that we sell to our clients, and sell services related to those products. They&amp;#8217;re doing well, so obviously, they must be solving a problem. So, from &amp;#8220;client&amp;#8221; point of view, the problem we solve is that of letting people who don&amp;#8217;t know anything about websites build and run complex websites.&lt;/p&gt;
&lt;p&gt;We have a &lt;span class="caps"&gt;CMS&lt;/span&gt; product that allows non web geeks manage websites. This includes writing new pages and editing content on existing pages, publishing news items, distributing these to an email list, managing uploaded files and inserting modules of dynamic content to their hearts desire. The modules we offer include contact forms, random image rotators, resume upload controls, auto-generating bread crumbs and menus, and so on. These modules aim to reduce the complexity of managing dynamic sites, so that ordinary people can do it.&lt;/p&gt;
&lt;p&gt;On top of that, we do custom applications built on top of that &lt;span class="caps"&gt;CMS&lt;/span&gt; site. Clients have a site they run themselves with the &lt;span class="caps"&gt;CMS&lt;/span&gt;, but some also have dedicated applications with a separate interface. These are separate because they&amp;#8217;re custom jobs. They provide functionality that is not available in the &lt;span class="caps"&gt;CMS&lt;/span&gt; (yet), or functionality that would be too complex to maintain using the &lt;span class="caps"&gt;CMS&lt;/span&gt;. So again, we&amp;#8217;re reducing the complexity of running a custom application.&lt;/p&gt;
&lt;p&gt;So, on first looks, we build websites and applications that non-geeks can use. But looking further, we manage complexity. We reduce the complexity for the client, so that the client can do difficult things with ease, and don&amp;#8217;t have to know &lt;em&gt;how&lt;/em&gt; it&amp;#8217;s done, only that they can do it.&lt;/p&gt;
&lt;p&gt;On the other hand, good programming is about managing complexity. That is, trying to keep your code as free from complexity as you can get away with while still doing the job. Complex code is buggy and unmaintainable.&lt;/p&gt;
&lt;p&gt;Complexity exists, and it is immutable. Once you&amp;#8217;ve simplified a task to the point that the only steps involved are those that accomplish that task, and that task cannot be accomplished without those steps, you have your complexity, and it isn&amp;#8217;t going anywhere. The task cannot be made more simple, because to do that we&amp;#8217;d have to leave out steps, which would not accomplish the task.&lt;/p&gt;
&lt;p&gt;What we do from then on is delegate complexity, shift it around and make it other people&amp;#8217;s problem. Take for example, the task of creating and publishing a blog post. Our software has tagging, categories, post titles and post content. Creating a post involves writing a post, giving it a title, adding tags, selecting categories and publishing it.&lt;/p&gt;
&lt;p&gt;Breaking it down, we need to create a body, create a title, create all categories, create all tags, link the tags to the post, link the post to the categories and publish it. Each link has a display name and a &lt;span class="caps"&gt;URL&lt;/span&gt; slug, and each category has a display name and a &lt;span class="caps"&gt;URL&lt;/span&gt; slug. &lt;span class="caps"&gt;URL&lt;/span&gt; slugs cannot contain certain characters, however their display names can.&lt;/p&gt;
&lt;p&gt;Now, we can delegate this complexity to the user, which will result in simple code. The user will be responsible for creating tags and categories, and giving them &lt;span class="caps"&gt;URL&lt;/span&gt; slugs that fit our rules, while the application will just take the data and store it, and retrieve it when asked. The user will be responsible for assigning tags to the post and the categories, and the application just stores it. This is obviously an unacceptable level of complexity for the user.&lt;/p&gt;
&lt;p&gt;We could also delegate all the complexity to the application, making the user experience simple. The user just types in the tags they want, picks the categories, and the application will link the tags if they exist, create them if they don&amp;#8217;t, automatically strip unwanted characters from &lt;span class="caps"&gt;URL&lt;/span&gt; slugs and hide a lot of the complexity. In more complicated cases, this will result in very complex code that will be bug prone.&lt;/p&gt;
&lt;p&gt;So the question is, where do we draw the line? What balance of code complexity and user interface complexity is successful? I guess you could say &amp;#8220;make it 50/50&amp;#8221; and think that&amp;#8217;s good enough, but I don&amp;#8217;t agree. I think the balance is very contextual, and often leans in favour of code complexity. In simple examples like above, taking on all the complexity of the task in the code is a trivial thing and easily done. For nuclear reactor control software, things might not be straight forward.&lt;/p&gt;
&lt;p&gt;This is the key to a successful software product/business, I think. Finding the right balance between complexity. If you put too much complexity on the user, user&amp;#8217;s won&amp;#8217;t be able to use it, and your software won&amp;#8217;t sell, and the whole thing will bomb. If you put too much complexity on the software, it will be buggy and difficult to maintain, and will eat up development time and money, and possibly even end up costing more than it earns, and then it will bomb. That&amp;#8217;s not even including the more personal aspects of programmer job satisfaction and sanity.&lt;/p&gt;
&lt;p&gt;Success is finding the sweet spot when balancing complexity.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=HDiCJ1Lhzgo:noczDCK6TSI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=HDiCJ1Lhzgo:noczDCK6TSI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=HDiCJ1Lhzgo:noczDCK6TSI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=HDiCJ1Lhzgo:noczDCK6TSI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=HDiCJ1Lhzgo:noczDCK6TSI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=HDiCJ1Lhzgo:noczDCK6TSI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=HDiCJ1Lhzgo:noczDCK6TSI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/HDiCJ1Lhzgo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/where-do-we-draw-the-line-on-complexity</feedburner:origLink></entry>
 
 <entry>
   <title>jQuery Context Menu Unbind Click Fix</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/BWAoTyTL4ms/jquery-context-menu-unbind-click-fix" />
   <updated>2009-04-09T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/jquery-context-menu-unbind-click-fix</id>
   <content type="html">&lt;p&gt;Updated on May 28, 2009, due to partial fix. The fix should now be a complete fix.&lt;br /&gt;
&amp;#8212;&lt;br /&gt;
Apologies for the somewhat confusing title.&lt;br /&gt;
I&amp;#8217;ve been doing a lot of jQuery work, replacing all the &lt;span class="caps"&gt;AJAX&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; crap in my project at work to speed the interface up. I&amp;#8217;ve started using the awesome &lt;a href="http://abeautifulsite.net/notebook/80"&gt;jQuery Context Menu&lt;/a&gt; plugin. However, I found it was also messing around with &lt;a href="http://www.jstree.com"&gt;jsTree&lt;/a&gt; which I am using on the same page.&lt;/p&gt;  &lt;p&gt;The problem is that the jQuery Context menu overzealously unbinds all click events from the document. This means that it&amp;#8217;s going to break all your other Javascript that relies on clicking. Checking the &lt;a href="http://docs.jquery.com/Events/unbind"&gt;documentation for jQuery&amp;#8217;s &lt;em&gt;unbind&lt;/em&gt; function&lt;/a&gt;, you can see that it accepts a function as a second parameter. This is the function that will be unbound if you pass that in as a parameter.&lt;br /&gt;
So, I fixed the jQuery Context Menu by changing the following:&lt;br /&gt;
&lt;ol&gt;   &lt;br /&gt;
&lt;li&gt;In the main &lt;em&gt;contextMenu&lt;/em&gt; function, near the end, just above the &lt;em&gt;return&lt;/em&gt; statement, I added the following:&lt;br /&gt;
[javascript]&lt;br /&gt;
// External click event for document &lt;br /&gt;
function onDocumentClick(e) {&lt;br /&gt;
      var menu = $(&amp;#8216;#&amp;#8217; + o.menu);&lt;br /&gt;
      $(document).unbind(&amp;#8216;click&amp;#8217;, onDocumentClick).unbind(&amp;#8216;keypress&amp;#8217;);&lt;br /&gt;
      $(menu).fadeOut(o.outSpeed);&lt;br /&gt;
      return false;&lt;br /&gt;
}     &lt;br /&gt;
[/javascript]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Next, I change the function that assigns the &lt;em&gt;click&lt;/em&gt; listener to the document to assign the defined function, instead of an anonymous function. So, change:      &lt;br /&gt;
[javascript]      &lt;br /&gt;
// Hide bindings&lt;br /&gt;
setTimeout( function() { // Delay for Mozilla&lt;br /&gt;
      $(document).click( function() {&lt;br /&gt;
            $(document).unbind(&amp;#8216;click&amp;#8217;).unbind(&amp;#8216;keypress&amp;#8217;);&lt;br /&gt;
            $(menu).fadeOut(o.outSpeed);&lt;br /&gt;
            return false;&lt;br /&gt;
      });&lt;br /&gt;
}, 0);&lt;br /&gt;
[/javascript]&lt;br /&gt;
to&lt;br /&gt;
[javascript] &lt;br /&gt;
// Hide bindings&lt;br /&gt;
setTimeout(function() { // Delay for Mozilla&lt;br /&gt;
      $(document).click(onDocumentClick);&lt;br /&gt;
}, 0);&lt;br /&gt;
[/javascript]&lt;/li&gt;    
&lt;li&gt;Lastly, I remove all instances of:     &lt;br /&gt;
[javascript]      &lt;br /&gt;
$(document).unbind(&amp;#8216;click&amp;#8217;);&lt;br /&gt;
[/javascript]&lt;/li&gt; 
&lt;/ol&gt;
&lt;p&gt;That&amp;#8217;s it. That fixed the problem for me. You&amp;#8217;ll notice I don&amp;#8217;t bother with the &lt;em&gt;keypress&lt;/em&gt; bindings. That&amp;#8217;s because I&amp;#8217;m not using them, so I&amp;#8217;m not bothered. I&amp;#8217;m assuming the fix for that will be a similar strategy, for those who are bothered.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve uploaded my version for those who can&amp;#8217;t get it working using the tips in this post, but remember the copyright remains with Cory S.N. LaViska over at &lt;a href="http://abeautifulsite.net/notebook/80"&gt;A Beautiful Site&lt;/a&gt;.&lt;br /&gt;
&lt;a href="http://www.timgittos.com/wordpress/wp-content/uploads/2009/04/jquerycontextmenu.js"&gt;jquery.contextMenu.js&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BWAoTyTL4ms:aExAtYnFoOA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BWAoTyTL4ms:aExAtYnFoOA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=BWAoTyTL4ms:aExAtYnFoOA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BWAoTyTL4ms:aExAtYnFoOA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=BWAoTyTL4ms:aExAtYnFoOA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BWAoTyTL4ms:aExAtYnFoOA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=BWAoTyTL4ms:aExAtYnFoOA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/BWAoTyTL4ms" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/jquery-context-menu-unbind-click-fix</feedburner:origLink></entry>
 
 <entry>
   <title>Correcting 5 Misconceptions About AI</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/dWraEaQKJJQ/correcting-5-misconceptions-about-ai" />
   <updated>2009-04-07T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/correcting-5-misconceptions-about-ai</id>
   <content type="html">&lt;p&gt;For the longest time, I have been interested in artificial intelligence. The idea of computers that could make decisions and think independently fascinated me. Of course, I knew that AI wasn&amp;#8217;t quite that advanced, but the idea still captivated me. However, the barrier to learning AI was too high. It was too complex and too academic. Just looking at the mathematical notation involved made my head spin.&lt;/p&gt;
&lt;p&gt;I eventually took the plunge and convinced my family to buy me &lt;a href="http://www.amazon.com/gp/product/0137903952?ie=UTF8&amp;tag=gebloftigi-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0137903952"&gt;Artificial Intelligence: A Modern Approach&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=gebloftigi-20&amp;l=as2&amp;o=1&amp;a=0137903952" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; for Christmas, and 12 months later, I actually started reading it. I&amp;#8217;m &lt;em&gt;still&lt;/em&gt; reading it, and will be the first to admit I don&amp;#8217;t understand everything that is discussed, however there are a few things that I&amp;#8217;m realising about AI.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;It&amp;#8217;s All About Searching&lt;/strong&gt;&lt;br /&gt;
Searching is a constant in AI techniques. Problems are defined and solution spaces are created. Problems can be represented in a number of ways (graphs, trees, logic knowledge bases), however in the end, it always comes back to searching.&lt;/p&gt;
&lt;p&gt;This is important because searching is easy. Searching is something that a lot of programmers already know, even if it&amp;#8217;s only at a most basic, brute force level. We do searching all the time. We loop through arrays searching for values, we use regular expressions to match string patterns, we retrieve records from databases. We search.&lt;/p&gt;
&lt;p&gt;At it&amp;#8217;s simplest, you can search using brute force searching, iterating over all combinations and permutations of solutions looking for one that satisfies the problem, but beyond that, you can involve tricky heuristics to make optimal decisions about how to search. You can have local searches, which will pick a solution space and search it for local maximums, such as hill climbing, and searches that will find global minimums, such as simulated annealing.  But it&amp;#8217;s still search. It&amp;#8217;s still something you can do.&lt;/p&gt;
&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;It&amp;#8217;s More Common Than You Think&lt;/strong&gt;&lt;br /&gt;
AI is a hell of a lot more prevalent than most people realise. I didn&amp;#8217;t think AI had much commercial application before I started learning about it, but luckily that didn&amp;#8217;t dim my interest. For those who are interested, but holding back because they don&amp;#8217;t see how it would benefit them, here&amp;#8217;s some good news. AI techniques are used everywhere. &lt;br /&gt;
&lt;br /&gt;
That international 4 city flight you booked used AI techniques. A constraint satisfaction problem solver took all the constraints about needing to be at this city by that time, flying on this airline for that much, and creating a plan for you. When Amazon recommends products you might be interested in, it calculates this with Bayesian networks and classifiers, a method of probabilistically linking a set of variables. Circuit design, product manufacturing, supply chain optimisation, all of these things use techniques that AI use. They&amp;#8217;re not the sole domain of AI, but learning AI will cause you to learn these too.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;You Can Use It Today&lt;/strong&gt;&lt;br /&gt;
Whatever you&amp;#8217;re working on, you can probably use AI techniques in it. Even some of the more exotic sounding techniques like neural networks can be of use to you. Self healing databases? &lt;a href="http://blip.tv/file/1947373/" title="Easy AI in Python"&gt;Hell yeah.&lt;/a&gt; Even Bayesian classifiers to catalog and categorise products, heuristic searches to mine data in databases, hierarchical task planners to plan that holiday or manage that Gantt chart.&lt;br /&gt;
&lt;br /&gt;
Can you use it anywhere? No. Your simple &lt;span class="caps"&gt;CRUD&lt;/span&gt; app probably won&amp;#8217;t benefit from a wizz-bang heuristic search. But if you&amp;#8217;re doing anything that involves large amounts of data, interacting with people, predicting trends and recognising patterns, you can use it.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;It&amp;#8217;s In Demand&lt;/strong&gt;&lt;br /&gt;
You may have heard of the &lt;a href="http://www.netflixprize.com/" title="Netflix Prize"&gt;Netflix Prize&lt;/a&gt;. Guess what? That&amp;#8217;s AI. Google is the biggest search engine around, and index billions upon billions of pages on the internet, and can get you relevant results to a question in a matter of seconds. That&amp;#8217;s one hell of a big knowledge base, and one smart search algorithm. Amazon sell products all over the world, and aggressively upsell and cross sell. I get emails about related products I might like based on my wishlist and purchase history, and they&amp;#8217;re actually pretty accurate.&lt;br /&gt;
&lt;br /&gt;
Also, computer games. Enough said.&lt;br /&gt;
&lt;br /&gt;
AI skills are in demand. Not huge demand, but probably more that you would have guessed. These skills are hugely profitable in the right hands, and big companies want to extract every single little morsel of useful information about your browsing, shopping, eating, travelling, viewing and reading habits in order to market to you more effectively. Now that sounds a little creepy to me, but if that doesn&amp;#8217;t bug you, more power.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;There&amp;#8217;s a Lot of Information Out There&lt;/strong&gt;&lt;br /&gt;
AI isn&amp;#8217;t some weirdo niche science topic. There&amp;#8217;s actually quite a lot of information out there, once you start going down the rabbit hole. &amp;#8220;AI: A Modern Approach&amp;#8221; cites hundreds of papers and books. There&amp;#8217;s thousands of websites out there on the subject. There are many academic papers that are made available for free online. There are communities, like &lt;a href="http://aigamedev.com" title="AI Game Dev"&gt;AIGameDev&lt;/a&gt;, dedicated to spreading that delicious knowledge.&lt;br /&gt;
&lt;br /&gt;
I think the hardest part about finding information is getting the terminology. It&amp;#8217;s pretty dense when you first get into it, especially when talking about acyclic directed graphs, and your idea of a graph was like mine was about a year ago, namely a few bars on a 2D Cartesian axis. But once you&amp;#8217;ve got a foot in the door of the lingo, it can become pretty accessible, and information starts becoming more bountiful. That foot in the door can be either a good, basic website, or in my case, a university level textbook &lt;em&gt;designed&lt;/em&gt; to introduce people to AI.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;AI is a big field, full of fascinating and interesting concepts and techniques, and it&amp;#8217;s a young field that&amp;#8217;s still full of potential. It&amp;#8217;s not as complex or confusing as film and television would have you think. That&amp;#8217;s not to say it&amp;#8217;s a walk in the park, as I stated earlier, I&amp;#8217;m probably running a 70% rate of understanding what I&amp;#8217;m reading, but I&amp;#8217;m managing. And if I can manage, so can you. So if you&amp;#8217;re interested, there&amp;#8217;s no better time to start than now.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=dWraEaQKJJQ:5iUiDTC4Lfc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=dWraEaQKJJQ:5iUiDTC4Lfc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=dWraEaQKJJQ:5iUiDTC4Lfc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=dWraEaQKJJQ:5iUiDTC4Lfc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=dWraEaQKJJQ:5iUiDTC4Lfc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=dWraEaQKJJQ:5iUiDTC4Lfc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=dWraEaQKJJQ:5iUiDTC4Lfc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/dWraEaQKJJQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/correcting-5-misconceptions-about-ai</feedburner:origLink></entry>
 
 <entry>
   <title>A CMS in Ruby on Rails, and Why I Stopped</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/vkBwoaxQ-yk/a-cms-in-ruby-and-why-i-stopped" />
   <updated>2009-04-06T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/a-cms-in-ruby-and-why-i-stopped</id>
   <content type="html">&lt;p&gt;For the last couple of months I have been writing a series of posts describing a personal Ruby on Rails based &lt;span class="caps"&gt;CMS&lt;/span&gt;. I have been writing tutorial style posts outlining what I was doing, and why I was doing it. Don&amp;#8217;t bother trying to look for those posts, because I&amp;#8217;ve archived them.&lt;/p&gt;
&lt;p&gt;This decision was pretty easy after I slowed down and reviewed the situation objectively for a few minutes. That clarity, coupled with a few truths that hit home while reading the source of a few other Rails applications pretty much sealed the deal.&lt;/p&gt;
&lt;p&gt;The next post in the series was going to be an overview of another Ruby &lt;span class="caps"&gt;CMS&lt;/span&gt; project, &lt;a href=""&gt;BrowserCMS&lt;/a&gt;. I saw a video from RailsConf about this project, and recognised a lot of their goals as coinciding with mine. So I was going to poke through their code, see how they&amp;#8217;ve done things, compare it to how I did the  same things, or was planning to do them.&lt;/p&gt;
&lt;p&gt;While I was reading through their source, it occurred to me just how much I don&amp;#8217;t get Rails. I have a bit of a poke around with scaffolding and get familiar enough with the generators and I decide that I&amp;#8217;m ready to tell people how do create a &lt;span class="caps"&gt;CMS&lt;/span&gt; in Ruby, because I&amp;#8217;ve nearly finished creating a &lt;span class="caps"&gt;CMS&lt;/span&gt; in &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s clear to me, now, how silly that was.&lt;/p&gt;
&lt;p&gt;Rails isn&amp;#8217;t just a framework for Ruby, it&amp;#8217;s a whole change in paradigm. Intellectually, I know Rails is &amp;#8220;opinionated software&amp;#8221;, however I don&amp;#8217;t think I understood what that really means. I tried to make my code as flexible and configurable as possible, and I was struggling with all but the most basic &lt;span class="caps"&gt;CRUD&lt;/span&gt; tasks.&lt;/p&gt;
&lt;p&gt;So, first I realised I wasn&amp;#8217;t ready to tell anyone how to do anything in Rails.&lt;/p&gt;
&lt;p&gt;But I have a series of about 5 posts doing just that. What do I do with those? Do I continue on, plugging away at learning while trying to instruct? I decided the answer to that depended on what I had achieved with my posts. What was the value of them?&lt;/p&gt;
&lt;p&gt;Then I realised that I had covered very little other than simple &lt;span class="caps"&gt;CRUD&lt;/span&gt;. Sure, I had some unusual object relations, like trees and self referential comments, and I implemented some business logic like compiling pages into templates, however the total sum of the non-&lt;span class="caps"&gt;CRUD&lt;/span&gt; related content could have fit into 1 post. So I spent 4 posts blathering away at how to achieve the same task as running &lt;em&gt;script/scaffold&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s worse is that I realised I was &lt;a href="http://www.timgittos.com/wordpress-or-roll-your-own"&gt;back in the rut of creating a &lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/a&gt;. How on earth did I do that again, after stating loudly and proudly that &lt;strong&gt;I don’t even like programming websites.&lt;/strong&gt;? Well, I told myself, you are planning on using this on your own sites, your many, many online business ideas. Sometimes you have to do the same old thing to earn money. Which is true, if I had done anything of worth, but I hadn&amp;#8217;t, I was a long winded scaffold script. I got carried away in the joy of learning a new language/framework (which isn&amp;#8217;t a bad thing), and fell into the familiar territory of doing what I always do (which &lt;strong&gt;is&lt;/strong&gt; a bad thing).&lt;/p&gt;
&lt;p&gt;So, now I realise that I&amp;#8217;m not only trying to teach people something I don&amp;#8217;t understand, I&amp;#8217;m trying to teach them how to do something I don&amp;#8217;t even like doing.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s stupid.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve archived the posts. I may revisit, as I still have grand ideas of what a &lt;span class="caps"&gt;CMS&lt;/span&gt; should be, but for now I&amp;#8217;m shelving the whole thing. Luckily I have such a small readership (read: none) at this stage, nobody will be affected. For that I&amp;#8217;m grateful.&lt;/p&gt;
&lt;p&gt;And yet, through all this stupidity, I have learnt a few things of value.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve learnt that Ruby on Rails is more complex than I thought, and will hit the books again to pick up some more advanced techniques.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve learnt that I&amp;#8217;m scared to push myself in programming. This revelation is a pointy one. I love programming, it&amp;#8217;s my job, it&amp;#8217;s my hobby and it&amp;#8217;s my passion. The fact that I&amp;#8217;m scared to push myself to innovate, hiding behind the excuse that I&amp;#8217;m not smart enough or I&amp;#8217;m not creative enough is double edged. On one hand, it&amp;#8217;s sad that I&amp;#8217;m not as ambitious as I thought. On the other, it&amp;#8217;s great that I know now, so that I can get stuck into remedying that.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve also learnt a lot about blogging. Those posts of mine weren&amp;#8217;t really providing much value. I don&amp;#8217;t have many readers because I&amp;#8217;m not saying anything new, and I&amp;#8217;m not showing anybody cool things they can&amp;#8217;t find in a hundred other blogs. I also didn&amp;#8217;t have much of a personal voice, and was writing them like I would a textbook, which is missing the point of a blog. It&amp;#8217;s supposed to be informal, and I&amp;#8217;m supposed to show my personality. So, I&amp;#8217;ve found my voice, while realising that I&amp;#8217;m not providing value. Another pointy idea, but ultimately good, because that too is something I can work on.&lt;/p&gt;
&lt;p&gt;So, inevitably, I have to question the value of &lt;strong&gt;this&lt;/strong&gt; post. What could this post provide to someone who stumbles across this website? Well, a few things.&lt;/p&gt;
&lt;p&gt;Firstly, self awareness is a great thing to possess as a programmer. If you know where your weaknesses are, you can train in them, and get better. But that&amp;#8217;s not enough, you also need to know what you&amp;#8217;re afraid of, so you can recognise that you don&amp;#8217;t even &lt;em&gt;know&lt;/em&gt; that it&amp;#8217;s a weakness. That fear hides the existence of the things you&amp;#8217;re not good of, and that&amp;#8217;s a major roadblock to improving.&lt;/p&gt;
&lt;p&gt;And lastly, if you don&amp;#8217;t have anything to add to the conversation, don&amp;#8217;t say anything. The whole internet is a conversation, and I&amp;#8217;ve just been babbling to myself in a corner the whole time. If you want to contribute, add your own thoughts, your own interpretation on subjects that are well known. Go into new levels of detail on old ideas and technologies. Introduce new ideas or technology, or modify existing ones. Contribute, don&amp;#8217;t just talk for the sake of talking.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=vkBwoaxQ-yk:s-jMDgS2bIo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=vkBwoaxQ-yk:s-jMDgS2bIo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=vkBwoaxQ-yk:s-jMDgS2bIo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=vkBwoaxQ-yk:s-jMDgS2bIo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=vkBwoaxQ-yk:s-jMDgS2bIo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=vkBwoaxQ-yk:s-jMDgS2bIo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=vkBwoaxQ-yk:s-jMDgS2bIo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/vkBwoaxQ-yk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/a-cms-in-ruby-and-why-i-stopped</feedburner:origLink></entry>
 
 <entry>
   <title>Visual Studio 2008 Deletes LINQ DBML Designer File</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/BeuY2gRH6II/visual-studio-2008-deletes-lin-dbml-designer-file" />
   <updated>2009-04-01T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/visual-studio-2008-deletes-lin-dbml-designer-file</id>
   <content type="html">&lt;p&gt;Do you spend hours wrangling with your &amp;#8220;Interactive&amp;#8221; Development Environment, trying to prevent it from deleting your boiler plate .designer file for your &lt;span class="caps"&gt;LINQ&lt;/span&gt; &lt;span class="caps"&gt;DBML&lt;/span&gt;? Do you get baffled watching Visual Studio delete said file from your software version control system, and then struggle to get the two back into sync?&lt;/p&gt;
&lt;p&gt;Then you might be encountering &lt;a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=361577"&gt;this bug&lt;/a&gt; right here. The reason for this post is because this bug seems very hard to find information on in Google. So hopefully I can raise some awareness, and at least have it pop up on a Google search.&lt;/p&gt;
&lt;p&gt;Typical symptoms are the designer file for the &lt;span class="caps"&gt;DBML&lt;/span&gt; being deleted when the &lt;span class="caps"&gt;DBML&lt;/span&gt; is updated. If you&amp;#8217;re also using source control, Visual Studio will attempt to delete it from your source control at the same time. Renaming the &lt;span class="caps"&gt;DBML&lt;/span&gt; file will cause it to regenerate, however it can cause major headaches when combined with source control, removing it, adding it, pending delete actions hidden in a project you thought you had unchecked out.&lt;/p&gt;
&lt;p&gt;The solution is the suitably moronic action of moving all your using statements inside your namespace declaration. A co-worker found this solution in &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/vs2008sp1beta/thread/40539acd-0216-4357-ac63-d507bf259c3d/"&gt;this &lt;span class="caps"&gt;MSDN&lt;/span&gt; forum thread&lt;/a&gt;. Once you move your usings, Visual Studio happily stops deleting your designer file, and you can finally get back to work programming instead of fighting your tools.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BeuY2gRH6II:9vK2PjGxR1U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BeuY2gRH6II:9vK2PjGxR1U:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=BeuY2gRH6II:9vK2PjGxR1U:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BeuY2gRH6II:9vK2PjGxR1U:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=BeuY2gRH6II:9vK2PjGxR1U:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=BeuY2gRH6II:9vK2PjGxR1U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=BeuY2gRH6II:9vK2PjGxR1U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/BeuY2gRH6II" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/visual-studio-2008-deletes-lin-dbml-designer-file</feedburner:origLink></entry>
 
 <entry>
   <title>In Defense of the Jerk</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/Lcj24Js1oUg/in-defense-of-the-jerk" />
   <updated>2009-03-29T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/in-defense-of-the-jerk</id>
   <content type="html">&lt;p&gt;Not just any jerk, but &lt;a href="http://sethgodin.typepad.com/seths_blog/2009/03/yeah-but-he-really-knows-his-stuff.html" title="Seth Godin's Blog - Yeah But He Really Knows His Stuff"&gt;the jerk who knows his stuff&lt;/a&gt;. The technically strong, socially weak programmer who does not play well with others.&lt;/p&gt;
&lt;p&gt;During a recent employee review, I was told that I need to work on a few areas, namely the way I communicate with my co-workers, and my tendencies to shoot down ideas without supplying alternatives. I was also told that my technical proficiency was more than sufficient.&lt;/p&gt;
&lt;p&gt;The technically capable but socially awkward programmer is a cliche in every day society, and the rogue programmer is a cliche in development teams. Seth Godin&amp;#8217;s post, and another one that cropped up in Hacker News reminded me of this, and made me think. I realised that, to some extend, I am that jerk.&lt;/p&gt;
&lt;p&gt;The point of this isn&amp;#8217;t to toot my own horn, rather to try to offer an explanation on behalf of all well-meaning jerks in software development teams. Now, I&amp;#8217;m not talking about those jerk jerks, who code maze-like code to secure themselves a job, those who are needlessly rude and abrasive, and those that ignore the other members of the team to the detriment of the whole project.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m talking about the jerks who are otherwise good employees. We&amp;#8217;re not trying to sabotage the project, to exert our will over the project, to make anyone feel bad or insufficient.&lt;/p&gt;
&lt;p&gt;We just care about the code.&lt;/p&gt;
&lt;p&gt;At least, I do. I care about what I&amp;#8217;m doing. I care about the project. I want my code to be the best code I&amp;#8217;ve ever written, I want this project to be the most successful project the company has.  I own my code, and take pride in it.&lt;/p&gt;
&lt;p&gt;When somebody suggests something that I know won&amp;#8217;t work, that will negatively affect the quality of the code, I freak out, somewhat. The first thing on my mind is to shoot down this idea, because I don&amp;#8217;t want it reducing the quality of the project.&lt;/p&gt;
&lt;p&gt;If my manager is planning on putting another programmer on the project with me, and I don&amp;#8217;t believe they&amp;#8217;re quite up to standard, I&amp;#8217;m going to try to limit the damage they do to the application. I&amp;#8217;m going to try and push them to work in a relatively isolated corner of the application. Unfortunately, I know this is a bad team work based attitude, however I can&amp;#8217;t help it.&lt;/p&gt;
&lt;p&gt;Now, I&amp;#8217;m not defending jerks. Being a jerk is a bad thing, I know this. I agree with what my boss said, and agree that I need to work on these areas. However, instantly firing the jerk, if they&amp;#8217;re a well meaning jerk, is not a good idea, because you&amp;#8217;ll lose someone who is passionate about what they do, and constantly striving to improve them.&lt;/p&gt;
&lt;p&gt;Instead, just try to work things through, and soften the edges of the jerk.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Lcj24Js1oUg:-SRon88ug9Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Lcj24Js1oUg:-SRon88ug9Q:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Lcj24Js1oUg:-SRon88ug9Q:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Lcj24Js1oUg:-SRon88ug9Q:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Lcj24Js1oUg:-SRon88ug9Q:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Lcj24Js1oUg:-SRon88ug9Q:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Lcj24Js1oUg:-SRon88ug9Q:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/Lcj24Js1oUg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/in-defense-of-the-jerk</feedburner:origLink></entry>
 
 <entry>
   <title>Parsing ASP.NET pages with SGMLParser</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/Lc8x04UfBa8/parsing-aspnet-pages-with-sgmlparser" />
   <updated>2009-03-09T00:00:00-07:00</updated>
   <id>http://www.timgittos.com/archives/parsing-aspnet-pages-with-sgmlparser</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m going to take a short break in my Ruby &lt;span class="caps"&gt;CMS&lt;/span&gt; series to post something I encountered at work.&lt;/p&gt;
&lt;p&gt;During my development of the &lt;span class="caps"&gt;CMS&lt;/span&gt; at work, I&amp;#8217;ve had to deal with parsing &lt;span class="caps"&gt;HTML&lt;/span&gt; content in order to compile page content into tags. This involves being able to replace certain elements of a page with other elements. At first I tried to do this with regular expressions, however this didn&amp;#8217;t turn out too well when it came to dealing with the inconsistencies in legacy sites running on the current, older &lt;span class="caps"&gt;CMS&lt;/span&gt;. Next, I tried parsing the pages as XDocuments, which worked ok as long as I was parsing well formed pages. As soon as it hit a malformed page, however, it died in a fiery burst of exceptions.&lt;/p&gt;
&lt;p&gt;Then I looked at SGMLParser, and it seemed like it was my savior. It parsed &lt;span class="caps"&gt;SGML&lt;/span&gt;, of which &lt;span class="caps"&gt;HTML&lt;/span&gt; is a subset, and it auto corrected malformed content, and would handle all the inconsistencies of life, in use &lt;span class="caps"&gt;HTML&lt;/span&gt;, and it would allow me to parse it into an XDocument so I can manipulate nodes. However, even SGMLParser had it&amp;#8217;s own problems: it wouldn&amp;#8217;t handle &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; server tags very well, which was a problem.&lt;/p&gt;
&lt;p&gt;We provide &amp;#8220;plug in&amp;#8221; functionality to &lt;span class="caps"&gt;CMS&lt;/span&gt; sites by the way of &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; server controls. You build your functionality, stick the server control files into your site, drop the binary into the bin folder and insert the server control tags into your page. Fire it up, and it will appear and function. However, when running pages with server control tags through the SGMLParser, it wouldn&amp;#8217;t recognise the namespaces, and would strip them, completely breaking them.&lt;/p&gt;
&lt;p&gt;This was unsatisfactory, as we were planning on using a similar sort of set up to perform the same thing in the new &lt;span class="caps"&gt;CMS&lt;/span&gt;. So, I hit Google, looking for ways to get around this. There&amp;#8217;s not a lot of information out there about it, other than &amp;#8220;&lt;span class="caps"&gt;SGML&lt;/span&gt; parses &lt;span class="caps"&gt;SGML&lt;/span&gt;, not &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt;, which isn&amp;#8217;t valid &lt;span class="caps"&gt;SGML&lt;/span&gt;&amp;#8221; which was exceedingly unhelpful, because I already know.&lt;/p&gt;
&lt;p&gt;I peeked into the source of SGMLReader to see if maybe I could remove the functionality that stripped out unknown namespaces. Sure, this would probably defeat the purpose of using SGMLParser, but it would help me out in this specific project. Unfortunately, the codebase is rather complicated and I really didn&amp;#8217;t want to dig in and spend hours on something I wasn&amp;#8217;t sure was even going to work.&lt;/p&gt;
&lt;p&gt;I saw that the project has a custom &lt;span class="caps"&gt;HTML&lt;/span&gt; dtd, so I considered briefly writing a dtd for &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt;. However, while I was thinking of all the different permutations of server tags, especially when you can specify your own namespaces and tag names and attributes, I quickly decided that wasn&amp;#8217;t suitable either.&lt;/p&gt;
&lt;p&gt;In the end, and I believe this is honestly the only way to do it, I ended up pre-processing my content, wrapping &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; server tags within &amp;lt;![&lt;span class="caps"&gt;CDATA&lt;/span&gt;[ ]]&amp;gt; tags. I noticed that SGMLParser was wrapping my older &amp;lt;% %&amp;gt; &lt;span class="caps"&gt;ASP&lt;/span&gt; style tags in this fashion, and leaving them unmolested. After I parse it into the XDocument, do my manipulations and pull it back out as the desired content, I run a post-process through it, removing the &amp;lt;![&lt;span class="caps"&gt;CDATA&lt;/span&gt;[ ]]&amp;gt; tags that were added in the pre-process. After, I&amp;#8217;m left with my content as it went in, with the modifications done through the compiling process.&lt;/p&gt;
&lt;p&gt;Of course, I do the pre-processing and post-processing with a regular expression:&lt;br /&gt;
[code language=&amp;#8220;html&amp;#8221;]&lt;br /&gt;
&amp;lt;/?[\w]+:[^&amp;gt;]*/?&amp;gt;&lt;br /&gt;
[/code] &lt;br /&gt;
which I think is kind of funny, in a way. I can never seem to escape regular expressions.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Lc8x04UfBa8:eQL8lDHmlu8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Lc8x04UfBa8:eQL8lDHmlu8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Lc8x04UfBa8:eQL8lDHmlu8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Lc8x04UfBa8:eQL8lDHmlu8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Lc8x04UfBa8:eQL8lDHmlu8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Lc8x04UfBa8:eQL8lDHmlu8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Lc8x04UfBa8:eQL8lDHmlu8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/Lc8x04UfBa8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/parsing-aspnet-pages-with-sgmlparser</feedburner:origLink></entry>
 
 <entry>
   <title>ASP.NET Ajax, FCKEditor and Firebug</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/imkO8zo7un4/aspnet-ajax-fckeditor-and-firebug" />
   <updated>2009-02-12T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/aspnet-ajax-fckeditor-and-firebug</id>
   <content type="html">&lt;p&gt;&lt;img src="/images/archives/firebugs.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Today at work I had the pleasure of dealing with a functionality bug in our new &lt;span class="caps"&gt;CMS&lt;/span&gt; that is written in &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt;. Our &lt;span class="caps"&gt;CMS&lt;/span&gt; uses FCKEditor for the rich text editor, and we&amp;#8217;re using a whole gang of &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; Ajax stuff for the interface. Specifically, we&amp;#8217;re using a TabContainer with user controls inside each tab.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;CMS&lt;/span&gt; is designed in the way that most CMS&amp;#8217;s are &amp;#8211; we have 2 major components. Page objects contain the content data of a page, so text, &lt;span class="caps"&gt;HTML&lt;/span&gt; meta data, etc. Template objects contain templates &amp;#8211; that is, &lt;span class="caps"&gt;HTML&lt;/span&gt; files with areas where you insert the page content, similar to how Dreamweaver does it&amp;#8217;s templates for you.&lt;/p&gt;
&lt;p&gt;When you publish a page/site, the &lt;span class="caps"&gt;CMS&lt;/span&gt; compiles the content into the template, then saves that as a file. When you&amp;#8217;re editing or creating a page in the admin interface, the application reads the content areas available in the current template you have selected for that page, and creates an FCKEditor dialog for it.&lt;/p&gt;
&lt;p&gt;Because you might not know how the content you&amp;#8217;re writing fits into the template you&amp;#8217;re going to use, we provide a preview function. This preview function will read in the content of the FCKEditor dialogs, create a temporary page object, set the src of an iframe to our preview page, which takes the page objects and feed it to a preview function which will compile the page and return the string, which we dump to the output stream of the preview page. We then fire up the iframe inside an &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; popup extender, for a nice modal preview.&lt;/p&gt;
&lt;p&gt;This all worked fine, until we got the tab container involved.&lt;/p&gt;
&lt;p&gt;In order to streamline the work flow and reduce the page refreshes on postbacks, we decided to put the content in a tab container, with different parts of the page in different tabs. When we did this, we noticed that when the preview button did a partial postback, it reloaded the FCKEditor dialogs from the database, obliterating the changes we made to the page (if any), or just displaying nothing for the content if it was a new page.&lt;/p&gt;
&lt;p&gt;This was just on my computer.&lt;/p&gt;
&lt;p&gt;On a co-workers computer, it worked perfectly as intended, despite the fact we were both working from the same source, in the same &lt;span class="caps"&gt;IDE&lt;/span&gt;, running it in the same browser. What gives?&lt;/p&gt;
&lt;p&gt;After poking around on both computers and trying the application in different browsers, we concluded that it doesn&amp;#8217;t work &lt;em&gt;only&lt;/em&gt; in my Firefox &amp;#8211; IE was fine on my computer, and all browsers were fine on his. Acting on a hunch, I disabled Firebug for my Firefox, because I noticed my co-worker didn&amp;#8217;t have Firebug installed.&lt;/p&gt;
&lt;p&gt;The application started working again.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t know why this happens, and why Firebug should be interfering with the Javascript in an obtrusive way, or even which Javascript it&amp;#8217;s interfering with. I don&amp;#8217;t know if Firebug was screwing with FCKEditor or &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; Ajax. So, this post is partially to put this info out there, in the hopes that someone else can answer for me.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s also partially to say, if you&amp;#8217;re seeing odd behavior that seems to be cropping up inconsistently across machines running Firefox, try disabling Firebug. Since being done by Firebug, I&amp;#8217;ve decided to leave it off during all development, and thinking back, I wonder how many other Javascript bugs I&amp;#8217;ve fought with that were caused by Firebug, and not the code.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=imkO8zo7un4:f4oNxoe84HE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=imkO8zo7un4:f4oNxoe84HE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=imkO8zo7un4:f4oNxoe84HE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=imkO8zo7un4:f4oNxoe84HE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=imkO8zo7un4:f4oNxoe84HE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=imkO8zo7un4:f4oNxoe84HE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=imkO8zo7un4:f4oNxoe84HE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/imkO8zo7un4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/aspnet-ajax-fckeditor-and-firebug</feedburner:origLink></entry>
 
 <entry>
   <title>Consistent Designs Across Browsers</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/jsE4gz-QfuU/consistent-designs-across-browsers" />
   <updated>2009-02-08T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/consistent-designs-across-browsers</id>
   <content type="html">&lt;p&gt;Firstly, a caveat: I am not a designer. I am a server side programmer who dabbles in web design and development. I do not know &lt;span class="caps"&gt;CSS&lt;/span&gt; as well as someone who designs websites for a living would. So take this advice with a grain of salt.&lt;/p&gt;
&lt;p&gt;Today @RealtorPaul asked why his site wasn&amp;#8217;t displaying right in Firefox, when it was displaying fine in IE. This is a common enough occurrence in web design, and it&amp;#8217;s due to the fact that different browser vendors use different render engines, and each render engine has it&amp;#8217;s own share of bugs.&lt;/p&gt;
&lt;p&gt;Bugs are qualified by measuring against a set of standards laid down by the W3C as a target for render engines. Among the various browsers, IE typically has the longest history of the worst standards support around, with IE 6 being the #1 criminal, and admittedly IE 7 is much better, but still flawed.&lt;/p&gt;
&lt;p&gt;When users develop a &lt;span class="caps"&gt;HTML&lt;/span&gt; interface that they check primarily against IE, testing how it looks in IE, etc, they&amp;#8217;ll often get a nasty shock when they check in a Gecko (Firefox, etc) browser, as their designs fall apart and generally look horrible.&lt;/p&gt;
&lt;p&gt;While the ideal way to trouble shoot these problems is to go over your &lt;span class="caps"&gt;CSS&lt;/span&gt; code with a fine tooth comb and understand how all the various rules are working, and understand how all the browsers render those rules, that&amp;#8217;s not very practical. Luckily, the 80/20 rule tends to come into play here, meaning the largest problems between browsers are caused by a small selection of things. Here is a list of things you can check against:&lt;br /&gt;
&lt;ul&gt;&lt;br /&gt;
	&lt;li&gt;&lt;strong&gt;Do you have a valid doctype in your &lt;span class="caps"&gt;HTML&lt;/span&gt; code?&lt;/strong&gt; A valid doctype will look like this: &lt;br /&gt;
&lt;pre class="html"&gt;&amp;lt;!&lt;span class="caps"&gt;DOCTYPE&lt;/span&gt; html &lt;span class="caps"&gt;PUBLIC&lt;/span&gt; &amp;#8220;-//W3C//&lt;span class="caps"&gt;DTD&lt;/span&gt; &lt;span class="caps"&gt;HTML&lt;/span&gt; 4.01//EN&amp;#8221; &lt;/pre&gt;&lt;br /&gt;
&lt;pre class="html"&gt;&amp;#8220;http://www.w3.org/TR/html4/strict.dtd&amp;#8221;&amp;gt;&lt;/pre&gt;&lt;br /&gt;
You can find a &lt;a title="Available doctypes for HTML pages." href="http://www.w3.org/QA/2002/04/valid-dtd-list.html"&gt;list of available doctypes at the W3C website&lt;/a&gt;. I personally recommend the &lt;span class="caps"&gt;HTML&lt;/span&gt; 4.01 doctype over the &lt;span class="caps"&gt;XHTML&lt;/span&gt; doctypes, for reasons that deserve a topic of their own. To use a doctype, put it as the first thing in every &lt;span class="caps"&gt;HTML&lt;/span&gt; page in your website.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;&lt;strong&gt;Are you using a lot of padding and margins?&lt;/strong&gt; One of the differences between Firefox and IE (just to name two) that most people hit is the difference in the box model.&lt;a title="Box model explanation - RedMelon.net" href="http://redmelon.net/tstme/box_model/"&gt; IE renders it&amp;#8217;s box model incorrectly&lt;/a&gt;, and as a result, can cause a lot of grief when using a lot of padding and margins. &lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;&lt;strong&gt;Are you using properties that do not have 100% support in all browsers?&lt;/strong&gt; Some &lt;span class="caps"&gt;CSS&lt;/span&gt; features are not implemented completely in all browsers, and their support is patchy at best. You can find a &lt;a title="CSS compatibility chart - Quirksmode.org" href="http://www.quirksmode.org/css/contents.html"&gt;list of these &lt;span class="caps"&gt;CSS&lt;/span&gt; features at quirksmode.org&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;&lt;strong&gt;Are you floating a lot of elements?&lt;/strong&gt; Floating elements removes them from the regular flow of the page, and as a result, can have some funky results on your design. Floating elements can be awesome when you know how to use it, but can be confusing as hell when you don&amp;#8217;t. &lt;a title="Things you should know about CSS floating - Smashing Mag" href="http://www.smashingmagazine.com/2007/05/01/css-float-theory-things-you-should-know/"&gt;Make sure you know what you&amp;#8217;re doing when you float stuff&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;&lt;strong&gt;Are you changing the flow of elements with the &amp;#8220;display&amp;#8221; property?&lt;/strong&gt; Certain elements are block level elements (they sit on their own line, and push elements beside them down) and some are inline elements (they happily co-exist in the middle of other elements). If you&amp;#8217;re changing how some elements display, be aware that other properties (I&amp;#8217;m looking at you, &amp;#8220;width&amp;#8221; and &amp;#8220;height&amp;#8221;) don&amp;#8217;t work on inline elements. &lt;a title="CSS: Block and Inline Elements - Web Design From Scratch" href="http://www.webdesignfromscratch.com/css-block-and-inline.php"&gt;Know what happens when you change how things are displayed&lt;/a&gt;.&lt;/li&gt;&lt;/p&gt;
&lt;/ul&gt;
&lt;p&gt;Those are the &lt;span class="caps"&gt;CSS&lt;/span&gt; concepts that get me the most. Many problems are solved just by adding a valid doctype to your page, however if you&amp;#8217;re still finding you&amp;#8217;re having problems, give the other items on the list a look.&lt;/p&gt;
&lt;p&gt;This list is &lt;em&gt;far &lt;/em&gt;from exhaustive, nor is it even very in depth. However, it&amp;#8217;s a good place to start looking, and it might point you in the right direction. With the state of the browser market as it is, debugging &lt;span class="caps"&gt;CSS&lt;/span&gt; is as much an art as creating the design for a site is.&lt;/p&gt;
&lt;p&gt;When debugging &lt;span class="caps"&gt;CSS&lt;/span&gt;, you might want to start with just bare bones &lt;span class="caps"&gt;HTML&lt;/span&gt;, and slowly add rules as you go, and isolate that way which rules are the ones that are messing everything up. Also, keep in mind that &lt;span class="caps"&gt;CSS&lt;/span&gt; is cascading &amp;#8211; which means you need to put your more specific rules at the bottom of your stylesheet, general rules at the top, otherwise your general rules will override your specific rules.&lt;/p&gt;
&lt;p&gt;The best way I&amp;#8217;ve found to debug &lt;span class="caps"&gt;CSS&lt;/span&gt; is to incrementally apply styles, and use a tool like &lt;a title="Firebug!" href="http://www.getfirebug.com/"&gt;Firebug &lt;/a&gt;to turn rules on and off dynamically, so you can see what happens. The most important thing to remember is that even experienced developers have to deal with browser incompatibility. If you find you&amp;#8217;re struggling, keep at it, and don&amp;#8217;t lose heart. It&amp;#8217;s all part of designing a website.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=jsE4gz-QfuU:-Mpi1fn3fes:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=jsE4gz-QfuU:-Mpi1fn3fes:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=jsE4gz-QfuU:-Mpi1fn3fes:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=jsE4gz-QfuU:-Mpi1fn3fes:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=jsE4gz-QfuU:-Mpi1fn3fes:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=jsE4gz-QfuU:-Mpi1fn3fes:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=jsE4gz-QfuU:-Mpi1fn3fes:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/jsE4gz-QfuU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/consistent-designs-across-browsers</feedburner:origLink></entry>
 
 <entry>
   <title>Apps Hungarian is Just Good Naming</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/XhOPQEqH7IQ/apps-hungarian-is-just-good-naming" />
   <updated>2009-02-06T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/apps-hungarian-is-just-good-naming</id>
   <content type="html">&lt;p&gt;&lt;a href="http://www.timgittos.com/wordpress/wp-content/uploads/2009/02/hungarian.jpg"&gt;&lt;img class="aligncenter size-full wp-image-206" title="Hungarian flag" src="http://www.timgittos.com/wordpress/wp-content/uploads/2009/02/hungarian.jpg" alt="Hungarian flag" width="500" height="257" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Application Hungarian is just good variable naming convention, but worse, because it&amp;#8217;s needlessly concise, and hard to read at a glance. It also comes from an environment that is growing more and more obsolete. More on that in a bit.&lt;/p&gt;
&lt;p&gt;Firstly, clarification is needed as to the definition of Application Hungarian notation, as opposed to Systems Hungarian. All of this is relatively useless, however, if you are in the same situation I was in a few years back and don&amp;#8217;t know what Hungarian notation even is.&lt;/p&gt;
&lt;p&gt;Hungarian notation is a variable and function naming convention where you add either prefixes or suffixes to names. What these prefixes/suffixes mean depends on what type of Hungarian notation you&amp;#8217;re using. Systems Hungarian is the method of adding information about the type of the value of a variable, or a return from a function. For example, a string that represents a name would be called &amp;#8220;strName&amp;#8221; using Systems Hungarian. Applications Hungarian is where you add information about the semantic meaning of the value of a variable.If this is a little foreign, that&amp;#8217;s because most people think Systems Hungarian when they think about Hungarian notation.&lt;/p&gt;
&lt;p&gt;In &lt;a href="http://www.joelonsoftware.com/articles/Wrong.html"&gt;Making Wrong Code Look Wrong&lt;/a&gt;, which is what inspired this post, Joel Spoelsky outlined exactly what Applications Hungarian notation is, and why it&amp;#8217;s so useful. He outlines that in Applications Hungarian, you add information about the semantic value of a variable/method return. To illustrate, he demonstrates that you can use Applications Hungarian to differentiate safe and unsafe strings in a web application environment. He uses the prefix &amp;#8216;s&amp;#8217; to define a &amp;#8220;safe&amp;#8221; string, that is safe against &lt;span class="caps"&gt;XSS&lt;/span&gt; attacks (ie: A html encoded string). He uses the &amp;#8216;us&amp;#8217; prefix to define an &amp;#8220;unsafe&amp;#8221; string, that is a string read directly from user input that may contain potentially dangerous code.&lt;/p&gt;
&lt;p&gt;Spolsky also demonstrates using the notation to make wrong code long wrong. That is, by combining prefixes on methods, based on their return types, you can use the names as a sort of litmus test. So if the return prefix of a function specifies it returns a &amp;#8216;us&amp;#8217; or unsafe string, and you assign it to a &amp;#8216;s&amp;#8217; or supposedly safe function, this is clearly a logic bug, and looks wrong.&lt;/p&gt;
&lt;p&gt;I think this is great, and it&amp;#8217;s something I&amp;#8217;ve never thought of, but my question is, how is it different from properly descriptive variable naming, aside from it&amp;#8217;s somewhat obscure brevity?&lt;/p&gt;
&lt;p&gt;The virtues of clear, descriptive names in programming have been sung again and again. If you make your variables and method names descriptive enough, your code becomes somewhat self documenting. You capture the intention and meaning in your code when you use variables like &amp;#8220;customerFirstName&amp;#8221; and &amp;#8220;formatAddress&amp;#8221;. You look at those names and you can immediately see the intention behind the code.&lt;/p&gt;
&lt;p&gt;I see a huge overlap between the best practice of descriptive variable naming and Spolsky&amp;#8217;s intention behind his use of Apps Hungarian, so much so that I don&amp;#8217;t see a difference between the two, with relation to their purported goals. Apps Hungarian is more terse, and more obscure, and has somewhat of a learning curve if you&amp;#8217;re not familiar with the nomenclature of the system. This, to me, seems like a needless barrier to understanding.&lt;/p&gt;
&lt;p&gt;Am I missing something? Why is Apps Hungarian better than regular, descriptive and intelligent variable naming? I can&amp;#8217;t see any benefit to using Apps Hungarian explicitly, and to my understanding, Apps Hungarian is just a more terse method of good variable naming.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=XhOPQEqH7IQ:2-rmYpCQGas:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=XhOPQEqH7IQ:2-rmYpCQGas:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=XhOPQEqH7IQ:2-rmYpCQGas:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=XhOPQEqH7IQ:2-rmYpCQGas:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=XhOPQEqH7IQ:2-rmYpCQGas:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=XhOPQEqH7IQ:2-rmYpCQGas:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=XhOPQEqH7IQ:2-rmYpCQGas:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/XhOPQEqH7IQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/apps-hungarian-is-just-good-naming</feedburner:origLink></entry>
 
 <entry>
   <title>Pixel Perfection is Impossible</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/psmGbVijLak/pixel-perfection-is-impossible" />
   <updated>2009-02-03T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/pixel-perfection-is-impossible</id>
   <content type="html">&lt;p&gt;This post is an elaboration of a comment that I left on a &lt;a title="Joren Rapini on CSS Frameworks" href="http://jorenrapini.com/blog/web-development/are-css-frameworks-really-worth-using"&gt;post about &lt;span class="caps"&gt;CSS&lt;/span&gt; frameworks&lt;/a&gt;. I agree wholeheartedly with Joren&amp;#8217;s position on &lt;span class="caps"&gt;CSS&lt;/span&gt; frameworks after having used &lt;a title="960gs CSS Grid Framework" href="http://960.gs/"&gt;960gs&lt;/a&gt; for the layout of this site (at the time of posting this).. As I mentioned in my reply to Joren&amp;#8217;s post, I used the framework to try to cut down the stress I feel when I try to make things line up properly and that most certainly didn&amp;#8217;t work as intended.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;img src="/images/archives/frustration.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Specifically, I have a little widget that shows my most recent tweet on the front page, and I&amp;#8217;m using a &lt;a title="Twitter bird vector images - Darkmotion.com" href="http://darkmotion.com/blog/2008/07/24/twitter-treat/"&gt;cute Twitter bird vector from DarkMotion.com&lt;/a&gt; as the background for this element. If you are viewing this post in IE, Chrome on a small resolution, and probably Opera and Safari, the bird is probably sitting obnoxiously below the recent post bar, getting in the way of content.&lt;/p&gt;
&lt;p&gt;This little bird has given me so much grief in the design of this site, that I&amp;#8217;ve thrown my hands up in despair and given up. The reason it&amp;#8217;s plagued me so is the way 960gs automatically floats everything for it&amp;#8217;s grid system. If you want to work outside the grid system, even a little bit, the framework makes you pay with blood.&lt;/p&gt;
&lt;p&gt;I love the bird, I love showing my most recent tweet. I will not remove it. However, I can&amp;#8217;t claim to be a serious developer, whilst still allowing obvious display bugs on the site, and I can&amp;#8217;t bring myself to use a third-party theme to represent my personal blog. It just seems wrong.&lt;/p&gt;
&lt;p&gt;In Joren&amp;#8217;s post, there is an excellent comment defending frameworks, which makes mention that Joren&amp;#8217;s blog has a 3 pixel difference in margins of the content, between the header and the footer. While I acknowledge that this wasn&amp;#8217;t the author&amp;#8217;s main point, it brings up something that I&amp;#8217;ve never understood in web design, and the mentality of many web designers, both new to design and coming from print design.&lt;/p&gt;
&lt;p&gt;A web page is a fluid medium. Web designers advocate abandoning the pixel for the em, citing greater flexibility and fluidity. So, at some level, they recognise this. However, people still insist on making designs that rely on pixel perfect precision positioning across all major browser vendors, which is where the need for &lt;span class="caps"&gt;CSS&lt;/span&gt; frameworks and reset stylesheets come from.&lt;/p&gt;
&lt;p&gt;Web browsers are products competing in a market, and they have different ways of rendering &lt;span class="caps"&gt;CSS&lt;/span&gt;, and they have their own unique quirks. We know this, as well. Beyond glaring &lt;span class="caps"&gt;CSS&lt;/span&gt; interpretation bugs and discrepancies in box models, they have unique margins and padding on elements, and sometimes these only differ by a few pixels.&lt;/p&gt;
&lt;p&gt;Why is this a problem?&lt;/p&gt;
&lt;p&gt;Why do these people feel the need to contort &lt;span class="caps"&gt;CSS&lt;/span&gt;, torture it into burying these differences, into displaying  the same across each browser. There are far too many permutations of resolution and browser, not to mention whether or not someone has their browser full screened (I don&amp;#8217;t) to try to enforce this pixel perfect design. &lt;/p&gt;
&lt;p&gt;Embrace the differences. Embrace the fact that your margins may not look identical. Recognise that at the design stage, and design your sites to compensate for this. Don&amp;#8217;t split images into different elements if they&amp;#8217;re intended to fit together seamlessly. Find another way. Don&amp;#8217;t stress if the margin between your content and your header is 3 pixels bigger on IE than it is in Firefox. As long as the general communication goals of your design work across all browsers, and it doesn&amp;#8217;t look like a train wreck, be happy.&lt;/p&gt;
&lt;p&gt;I know all of this is easier said than done. I&amp;#8217;m a server side programmer, not a &lt;span class="caps"&gt;CSS&lt;/span&gt; guru or a designer. However, I think it&amp;#8217;s a worthy to keep in mind while designing. Don&amp;#8217;t fight the diversity, embrace it.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=psmGbVijLak:vWQzBR7Qi5E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=psmGbVijLak:vWQzBR7Qi5E:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=psmGbVijLak:vWQzBR7Qi5E:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=psmGbVijLak:vWQzBR7Qi5E:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=psmGbVijLak:vWQzBR7Qi5E:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=psmGbVijLak:vWQzBR7Qi5E:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=psmGbVijLak:vWQzBR7Qi5E:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/psmGbVijLak" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/pixel-perfection-is-impossible</feedburner:origLink></entry>
 
 <entry>
   <title>C# Interface Method Gotcha When Inheriting</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/5q4gDSLRUSQ/csharp-interface-method-gotcha-when-inheriting" />
   <updated>2009-02-02T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/csharp-interface-method-gotcha-when-inheriting</id>
   <content type="html">&lt;p&gt;I noticed some interesting behavior from C# yesterday at work. Truth be told, I&amp;#8217;ve noticed this in the past, but I&amp;#8217;ve only figured out what&amp;#8217;s causing it today.&lt;/p&gt;
&lt;p&gt;The behavior is this: &lt;strong&gt;when you inherit from a class that implements an interface, calling a hidden/overriden method from an object of the inheriting class that has been upcast to the interface will result in a call the the inherited function.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ok, so that probably made no sense at all, which is why I will explain it, but not before a warning. I&amp;#8217;m not sure if this is intended behavior, and I&amp;#8217;m not sure if this is something I&amp;#8217;m doing wrong. If someone can point me in the direction of an explanation or a correction, I would be very grateful.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/archives/bugs.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;On to the explanation.&lt;/p&gt;
&lt;p&gt;Take a sample, trivial application that has widgets. These widgets just print messages out to the console. We have an interface, &lt;strong&gt;IWidget&lt;/strong&gt;, which forms the contract for all widgets:&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='C'&gt;interface IWidget
{
    void DoSomething();
    void DoSomethingElse();
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Next, we have a generic widget class, which we use for most widgets. This is called &lt;strong&gt;GenericWidget&lt;/strong&gt;:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='C'&gt;class GenericWidget : IWidget
&lt;p&gt;{&lt;br /&gt;
    public void DoSomething()&lt;br /&gt;
    {&lt;br /&gt;
        Console.WriteLine(&amp;quot;Doing something in GenericWidget&amp;quot;);&lt;br /&gt;
    }&lt;/p&gt;
&lt;p&gt;    public void DoSomethingElse()&lt;br /&gt;
    {&lt;br /&gt;
        Console.WriteLine(&amp;quot;Doing something else in GenericWidget&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;And finally, we have a specific type of widget that does something different, called &lt;strong&gt;SpecificWidget&lt;/strong&gt;:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='c'&gt;class SpecificWidget : GenericWidget
&lt;p&gt;{&lt;br /&gt;
    public new void  DoSomething()&lt;br /&gt;
    {&lt;br /&gt;
        Console.WriteLine(&amp;quot;Doing something in SpecificWidget&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    public new void DoSomethingElse()&lt;br /&gt;
    {&lt;br /&gt;
    Console.WriteLine(&amp;quot;Doing something else in SpecificWidget&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now, we want to run some tests on our widgets, to see what&amp;#8217;s going on. First, we&amp;#8217;ll test the widgets themselves. Running:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;&lt;code class='c'&gt;GenericWidget genericWidget = new GenericWidget();
&lt;p&gt;genericWidget.DoSomething();&lt;br /&gt;
genericWidget.DoSomethingElse();&lt;/p&gt;
&lt;p&gt;SpecificWidget specificWidget = new SpecificWidget();&lt;br /&gt;
specificWidget.DoSomething();&lt;br /&gt;
specificWidget.DoSomethingElse();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;will output:&lt;br /&gt;
&lt;blockquote&gt;Doing something in GenericWidget&lt;br /&gt;
Doing something else in GenericWidget&lt;/p&gt;
&lt;p&gt;Doing something in SpecificWidget&lt;br /&gt;
Doing something else in SpecificWidget &lt;/blockquote&gt;&lt;br /&gt;
 Which is exactly what we expected to see. Test has passed.&lt;/p&gt;
&lt;p&gt;Next, lets say we have a function that we want to pass widgets to, but we don&amp;#8217;t know what kind of widgets we will be passing, only that they are widgets. So we pass them as widgets, but upcast them to IWidget, and call the methods on them from the interface. For example:&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='c'&gt;IWidget genericUpcast = new GenericWidget();
genericUpcast.DoSomething();
genericUpcast.DoSomethingElse();&lt;/p&gt;
&lt;p&gt;IWidget specificUpcast = new SpecificWidget();&lt;br /&gt;
specificUpcast.DoSomething();&lt;br /&gt;
specificUpcast.DoSomethingElse();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;which will give the following output:&lt;br /&gt;
&lt;blockquote&gt;Doing something in GenericWidget&lt;br /&gt;
Doing something else in GenericWidget&lt;/p&gt;
&lt;p&gt;Doing something in GenericWidget&lt;br /&gt;
Doing something else in GenericWidget&lt;/blockquote&gt;&lt;br /&gt;
Wait, that&amp;#8217;s not right. The specificUpcast should call the method on SpecificWidget, shouldn&amp;#8217;t it? At least, that&amp;#8217;s &lt;em&gt;my &lt;/em&gt;expected behavior. Just to prove there&amp;#8217;s not something wrong with our specificUpcast:&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
  &lt;pre&gt;&lt;code class='C'&gt;(specificUpcast as SpecificWidget).DoSomething();
(specificUpcast as SpecificWidget).DoSomethingElse();&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;will yield:&lt;br /&gt;
&lt;blockquote&gt;Doing something in SpecificWidget&lt;br /&gt;
Doing something else in SpecificWidget &lt;/blockquote&gt;&lt;br /&gt;
which is our expected output all along.&lt;/p&gt;
&lt;p&gt;If someone can explain this to me, or point me to a better method to upcast, then please do so. I&amp;#8217;m finding a lot of my code needs to check for specific types in order to call the proper method, and it seems clunky and awkward. I&amp;#8217;m sure I&amp;#8217;m doing something wrong, I&amp;#8217;m just not sure what.&lt;/p&gt;
&lt;p&gt;As usual, you can find the source code here: &lt;a href="/files/archives/gotcha.zip"&gt;Interface Upcasting Inherited Classes Gotcha&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=5q4gDSLRUSQ:J-lKpSqs04M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=5q4gDSLRUSQ:J-lKpSqs04M:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=5q4gDSLRUSQ:J-lKpSqs04M:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=5q4gDSLRUSQ:J-lKpSqs04M:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=5q4gDSLRUSQ:J-lKpSqs04M:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=5q4gDSLRUSQ:J-lKpSqs04M:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=5q4gDSLRUSQ:J-lKpSqs04M:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/5q4gDSLRUSQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/csharp-interface-method-gotcha-when-inheriting</feedburner:origLink></entry>
 
 <entry>
   <title>Using Twitter to Gather Information</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/r78TUz6W5vY/using-twitter-to-gather-information" />
   <updated>2009-01-30T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/using-twitter-to-gather-information</id>
   <content type="html">&lt;p&gt;&lt;a href="http://www.timgittos.com/wp-content/uploads/2009/01/birds.jpg"&gt;&lt;/a&gt;&lt;a href="http://www.timgittos.com/wordpress/wp-content/uploads/2009/01/birds.jpg"&gt;&lt;img class="aligncenter size-full wp-image-184" title="Birds" src="http://www.timgittos.com/wordpress/wp-content/uploads/2009/01/birds.jpg" alt="Birds" width="450" height="253" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve mentioned briefly the virtues I see in Twitter when I discussed &lt;a title="Implementing an Idea in 3 hours with Ruby - TimGittos.com" href="http://www.timgittos.com/3-hours-from-concept-to-implementation-with-ruby"&gt;how to implement a project in 3 hours&lt;/a&gt;. Now I want to expand on how to use Twitter to gather information. I mentioned in that the key to utilising Twitter to gather information was to follow the right kinds of people. However, you&amp;#8217;ll find that when you start following more than 100 people, things get a little hectic.&lt;/p&gt;
&lt;p&gt;Every programmer is more effective with a solid selection of tools, and Twitter is no different. &lt;a title="Tweetdeck" href="http://www.tweetdeck.com/beta/"&gt;TweetDeck&lt;/a&gt; is the best Twitter desktop client I&amp;#8217;ve used, and it&amp;#8217;s an &lt;span class="caps"&gt;AIR&lt;/span&gt; app, so it runs on all major operating systems. Most Twitter clients have a single stream that Tweets come in through, and everything gets lumped together. TweetDeck&amp;#8217;s strongest feature, for the purposes of leveraging Twitter to gather information, is the option of splitting your stream into groups.&lt;/p&gt;
&lt;p&gt;TweetDeck allows you to put people you follow into groups, and have their tweets appear in a different window. The notification alert will also show this segregation. In addition to splitting your followers, you can specify windows that will feed you the results of searches, using the Twitter search operators outlined &lt;a href="http://search.twitter.com/operators"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The search operators and TweetDeck are the engine of our information gathering machine. Using the search operators you can follow the public stream and cherry pick Tweets that contain information you want. You can look for specific phrases, specific hashtags, tweets after a certain date and tweets with links.&lt;/p&gt;
&lt;p&gt;For example, I use use a search for &amp;#8220;artificial intelligence&amp;#8221; with links to find people who tweet interesting links concerning artificial intelligence, which is a subject I&amp;#8217;m highly interested in. I can run several of these filters in different windows at the same time, and grok the whole public stream. No longer am I restricted to listening only to those that I follow. Of course, that&amp;#8217;s not to say I no longer follow people. If someone pops up multiple times in my filters, I&amp;#8217;ll follow them to be sure not to miss a single tweet from them.&lt;/p&gt;
&lt;p&gt;This method, however, isn&amp;#8217;t flawless. If you look too narrowly, you won&amp;#8217;t find any tweets. Also, when you finally do find tweets, even by trying to pick out key phrases/keywords and links, there will be a significant signal to noise ratio. My search for AI topics often lead to students linking university class websites and time tables, which is something I&amp;#8217;m obviously not interested in. Often people who pop up in searches all the time turn out to have a high noise to signal ratio.&lt;/p&gt;
&lt;p&gt;Having said that, while there are drawbacks, the ability to monitor the public stream as well as the people you follow, and sift out tweets that have a higher likelihood of being relevant is a powerful thing, and will often connect you to bits of information you would have never found otherwise. That&amp;#8217;s the power of Twitter, and that&amp;#8217;s why I love Twitter.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=r78TUz6W5vY:u-7xv0Fgj5w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=r78TUz6W5vY:u-7xv0Fgj5w:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=r78TUz6W5vY:u-7xv0Fgj5w:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=r78TUz6W5vY:u-7xv0Fgj5w:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=r78TUz6W5vY:u-7xv0Fgj5w:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=r78TUz6W5vY:u-7xv0Fgj5w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=r78TUz6W5vY:u-7xv0Fgj5w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/r78TUz6W5vY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/using-twitter-to-gather-information</feedburner:origLink></entry>
 
 <entry>
   <title>3 Hours from Concept To Implementation With Ruby</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/RSAb_WjU8wQ/3-hours-from-concept-to-implementation-with-ruby" />
   <updated>2009-01-27T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/3-hours-from-concept-to-implementation-with-ruby</id>
   <content type="html">&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.timgittos.com/wordpress/wp-content/uploads/2009/01/ruby.jpg"&gt;&lt;img class="aligncenter size-full wp-image-186" title="Ruby" src="http://www.timgittos.com/wordpress/wp-content/uploads/2009/01/ruby.jpg" alt="Ruby" width="450" height="284" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Although I&amp;#8217;m still relatively new to it, I&amp;#8217;m a big fan of Twitter. However, not for the social media aspects of it. I view Twitter as an excellent method of gathering information, as long as you follow the right kinds of people. By the right kinds of people, I mean people who tweet interesting links they find online. Simply follow people who are interested or involved in the same subjects that you&amp;#8217;re interested in, and they will feed you information over time, in a nice steady flow.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m very much interested in AI, and AI as it applies to games. I am a fee paying member of Alex J. Champandard&amp;#8217;s &lt;a title="AIGameDev" href="http://www.aigamedev.com"&gt;AIGameDev&lt;/a&gt; and I follow him on &lt;a href="http://twitter.com/aigamedev"&gt;Twitter&lt;/a&gt;. While this is great, his flow of information isn&amp;#8217;t fast enough for me. So I set to Twitter to search for people who are interested in AI and game development, when I found the @playwitter account, and the &lt;a title="Playwitter - following game development on Twitter" href="http://playwitter.com/"&gt;associated website&lt;/a&gt;. As you can see from the @playwitter tweet, they&amp;#8217;re not yet fully functional. I didn&amp;#8217;t really want to wait, and I didn&amp;#8217;t really want to follow all those people on my own. So I decided to come up with an intermediary solution.&lt;/p&gt;
&lt;p&gt;The concept is a Twitter bot that will read in an &lt;span class="caps"&gt;RSS&lt;/span&gt; feed and tweet the entries. I decided to use Ruby, as I haven&amp;#8217;t done any significant programming in Ruby before. &lt;a title="My First Impression of Ruby - timgittos.com" href="http://www.timgittos.com/first-impressions-of-ruby"&gt;All I knew was the basic syntax&lt;/a&gt; that I read from the &lt;a href="http://www.amazon.com/gp/product/0974514055?ie=UTF8&amp;amp;tag=gebloftigi-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0974514055"&gt;Pickaxe&lt;/a&gt; book.&lt;/p&gt;
&lt;p&gt;First, I hit Google looking for a Ruby &lt;span class="caps"&gt;RSS&lt;/span&gt; parser library. Oh! It turns out Ruby has one built into the language. So I read a few websites on how to do that, and it seems pretty straight forward. So I grab the feed over at Playwitter and start pulling it down with my Ruby script. The quick script I wrote in 10 minutes worked like a charm.&lt;/p&gt;
&lt;p&gt;The next part was to tweet the entries. I looked for a Twitter library and settled on the &lt;a title="Ruby Twitter Gem" href="http://twitter.rubyforge.org/"&gt;Twitter gem&lt;/a&gt;. I installed the gem, and this took me a while to get it working as a library, but get it working I did. I was able to send tweets from an automated script.&lt;/p&gt;
&lt;p&gt;It took me about half an hour to wire these together and before I knew it, I was done. However, it was fairly crude, and I found out when I tried to deploy it to my server that it wouldn&amp;#8217;t make the grade. I set about refactoring and upgrading the code and trying to get it run. 3 hours later, it was complete, and it was working.&lt;/p&gt;
&lt;p&gt;In the end, I implemented the idea in 3 hours, with the following features:&lt;br /&gt;
&lt;ul&gt;&lt;br /&gt;
	&lt;li&gt;&lt;span class="caps"&gt;YAML&lt;/span&gt; config file for defining Twitter account details and &lt;span class="caps"&gt;RSS&lt;/span&gt; feeds to tweet from.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;Timestamp based polling of the &lt;span class="caps"&gt;RSS&lt;/span&gt; feeds, storing only updates new since the last poll.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;Tweeting with added hashtag, defined in the &lt;span class="caps"&gt;YAML&lt;/span&gt; with the feed&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;Deployment as a Ruby Gem&lt;/li&gt;&lt;/p&gt;
&lt;/ul&gt;
&lt;p&gt;Details of the project are the subject of another post, and when that project is a little mature, I will create that post.&lt;/p&gt;
&lt;p&gt;From concept to deployment on a live site, with a basic knowledge of Ruby only, in 3 hours. That&amp;#8217;s a fantastic result that I&amp;#8217;ve never experienced in another language, compiled or not. It was fun, it was fast, and I felt the freedom of &lt;span class="caps"&gt;PHP&lt;/span&gt; with the benefit of a well implemented OO system.&lt;/p&gt;
&lt;p&gt;Man, I love Ruby.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=RSAb_WjU8wQ:9ILwNs7IoeE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=RSAb_WjU8wQ:9ILwNs7IoeE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=RSAb_WjU8wQ:9ILwNs7IoeE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=RSAb_WjU8wQ:9ILwNs7IoeE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=RSAb_WjU8wQ:9ILwNs7IoeE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=RSAb_WjU8wQ:9ILwNs7IoeE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=RSAb_WjU8wQ:9ILwNs7IoeE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/RSAb_WjU8wQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/3-hours-from-concept-to-implementation-with-ruby</feedburner:origLink></entry>
 
 <entry>
   <title>Frameworks Make Reading New Code Hard</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/XC4sdEnmq9c/frameworks-make-reading-new-code-hard" />
   <updated>2009-01-24T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/frameworks-make-reading-new-code-hard</id>
   <content type="html">&lt;p&gt;In an effort to increase my knowledge of both Ruby and Rails, I have been keeping my eyes open for interesting Ruby/Rails apps to peek at the source code of. Whilst looking at @j_stirk&amp;#8217;s &lt;a title="Jason Stirk's Blog" href="http://griffin.oobleyboo.com/"&gt;website&lt;/a&gt;, I noticed it was running on &lt;a title="Radiant CMS - Ruby CMS" href="http://radiantcms.org/"&gt;Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/a&gt;, a Ruby &lt;span class="caps"&gt;CMS&lt;/span&gt;. So, I grabbed a copy of the source code.&lt;/p&gt;
&lt;p&gt;Whilst I was having a peek at the source, I began to think that I was in a little over my head. I managed to muddle my way through the config/routes.rb file and figure out (with judicious use of Google) what requests were being directed to what controllers. The problems started happening when I hit the controller, and started seeing filters and symbols and statements that I didn&amp;#8217;t know where to go next to find out about.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.timgittos.com/wordpress/wp-content/uploads/2009/01/confused1.jpg"&gt;&lt;img class="aligncenter size-full wp-image-191" title="Confusion" src="http://www.timgittos.com/wordpress/wp-content/uploads/2009/01/confused1.jpg" alt="Confusion" width="400" height="288" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At first I thought it was to do with the fact that I don&amp;#8217;t really know Ruby. I know enough to recognise it, and muddle through basic syntax, but I don&amp;#8217;t know any tricks, any coding conventions and the nuances of Ruby programming. However, upon reflecting on my dilemma, I realised this isn&amp;#8217;t something that was restricted to Ruby, Rails and Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I remember last year looking into &lt;a title="PHP application framework" href="http://www.symfony-project.org/"&gt;Symfony&lt;/a&gt;, before deciding that &lt;span class="caps"&gt;PHP&lt;/span&gt; was too god-awful ugly to waste my time on. I recall that too had a fairly high learning curve, and looking through an existing Symfony app, it was very hard to figure out what exactly was going on. There was much &lt;span class="caps"&gt;API&lt;/span&gt; browsing.&lt;/p&gt;
&lt;p&gt;A few years ago when I first learnt &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt;, I was in a similar situation. Server tags and user controls and page events and assemblies were all very new and very confusing to this ex-&lt;span class="caps"&gt;PHP&lt;/span&gt; &amp;amp; &lt;span class="caps"&gt;ASP&lt;/span&gt; 3.0 developer. I stormed through a book on &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; and was thrown head first into a contracting gig before catching my stride again.&lt;/p&gt;
&lt;p&gt;I love frameworks. Ever since I heard about this thing called &amp;#8220;Rails&amp;#8221; a few years back, and realised there were a few similar frameworks written in &lt;span class="caps"&gt;PHP&lt;/span&gt;, I&amp;#8217;ve been in love with frameworks. And I&amp;#8217;ve always learnt them from the ground up, creating my own application. Last night was the first time I&amp;#8217;ve ever tried to learn a framework from an application.&lt;/p&gt;
&lt;p&gt;And it&amp;#8217;s hard.&lt;/p&gt;
&lt;p&gt;While frameworks increase programmer productivity and make maintenance easier for programmers who already are in the know, they make things really hard for a new maintainer who is not familiar with the code to dive in and figure out what&amp;#8217;s going on. Not only do they have to learn the individual nuances of the programmer who wrote the application, they also have to figure out how the framework works.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=XC4sdEnmq9c:urmDQiIRfNE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=XC4sdEnmq9c:urmDQiIRfNE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=XC4sdEnmq9c:urmDQiIRfNE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=XC4sdEnmq9c:urmDQiIRfNE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=XC4sdEnmq9c:urmDQiIRfNE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=XC4sdEnmq9c:urmDQiIRfNE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=XC4sdEnmq9c:urmDQiIRfNE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/XC4sdEnmq9c" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/frameworks-make-reading-new-code-hard</feedburner:origLink></entry>
 
 <entry>
   <title>Reconciling YAGNI With Reversibility</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/SodCQ8b2uZA/reconciling-yagni-with-reversibility" />
   <updated>2009-01-21T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/reconciling-yagni-with-reversibility</id>
   <content type="html">&lt;p&gt;Yesterday I started reading Andrew Hunt&amp;#8217;s &lt;a href="http://www.amazon.com/gp/product/020161622X?ie=UTF8&amp;amp;tag=gebloftigi-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=020161622X"&gt;The Pragmatic Programmer&lt;/a&gt;&lt;img style="border:none !important; margin:0px !important;" src="http://www.assoc-amazon.com/e/ir?t=gebloftigi-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=020161622X" border="0" alt="" width="1" height="1" /&gt;, which has been sitting around waiting to be read for at least several months. Every programmer I talk to says that it&amp;#8217;s a book that will really stimulate growth as a programmer, and I certainly need to grow.&lt;/p&gt;
&lt;p&gt;Already several of the things the author has said have rung true, and I can see many of the scenarios he&amp;#8217;s described as having happened, or nearly happened, in a few of the projects I myself has been involved with. Which is exactly what has piqued this post.&lt;/p&gt;
&lt;p&gt;Hunt outlines the need for what he calls &lt;strong&gt;reversibility&lt;/strong&gt;. He states that there are critical decisions to be made in each project, and each of these involves a commitment that often isn&amp;#8217;t easily changed, such as committing to a type of database, or committing to a design pattern.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.timgittos.com/wordpress/wp-content/uploads/2009/01/cat.jpg"&gt;&lt;img class="aligncenter size-full wp-image-193" title="Cat in a Box" src="http://www.timgittos.com/wordpress/wp-content/uploads/2009/01/cat.jpg" alt="Cat in a Box" width="375" height="250" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;He goes on to describe the need for a Schrödinger&amp;#8217;s Cat approach to software design. The basis is the &lt;a title="Schrödinger's Cat - Wikipedia" href="http://en.wikipedia.org/wiki/Schrödinger's_cat"&gt;Schrödinger&amp;#8217;s Cat&lt;/a&gt; theory which illustrates quantum superposition &amp;#8211; where at the point of a decision, multiple dimensions spawn off and you don&amp;#8217;t know which dimension you&amp;#8217;re in until the decision is observed.&lt;/p&gt;
&lt;p&gt;Hunt argues that we should design code to be flexible enough to allow as many of the &amp;#8220;possible dimensions&amp;#8221; as possible. What he means by this is to allow for these critical decisions to be changed, with minimal impact on the code, hence the term &lt;strong&gt;reversibility&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To do this, we should code for possibilities. We should always keep in mind what might happen, and design our software so that we can accommodate the change. This flies directly into the face of another principle of programming, &lt;a title="You Ain't Gonna Need It - Wikipedia" href="http://en.wikipedia.org/wiki/You_Ain't_Gonna_Need_It"&gt;You Ain&amp;#8217;t Gonna Need It (&lt;span class="caps"&gt;YAGNI&lt;/span&gt;)&lt;/a&gt;, and the general belief that the more code you write, the more opportunity there is to introduce bugs in code (something Hunt himself mentions).&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;YAGNI&lt;/span&gt; outlines that you shouldn&amp;#8217;t write code you don&amp;#8217;t need, and cites several reasons why, and coupled along with the idea of writing less code is better, this is something I believe. However Hunt&amp;#8217;s Reversibility idea is in almost direct opposition &amp;#8211; he advocates writing code &amp;#8220;just in case.&amp;#8221;&lt;/p&gt;
&lt;p&gt;Can these two ideas be reconciled?&lt;/p&gt;
&lt;p&gt;I believe they can, and it&amp;#8217;s an approach I&amp;#8217;ve used in the past. I&amp;#8217;ve found that it&amp;#8217;s possible to quickly and safely recognise that there is the possibility of a change by writing interfaces and method stubs for new functionality, and have them throw not-implemented exceptions.&lt;/p&gt;
&lt;p&gt;This way, you acknowledge that a decision might be changed and have already got the application hooks to hook into it, but you haven&amp;#8217;t wasted time implementing something that may not come to pass. Your software will build, and at the existing functionality won&amp;#8217;t be broken while you wait to implement these new changes.&lt;/p&gt;
&lt;p&gt;This seems like a trivial thing to do, however it can really streamline the process in my experience.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=SodCQ8b2uZA:rjibrpXB2Lo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=SodCQ8b2uZA:rjibrpXB2Lo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=SodCQ8b2uZA:rjibrpXB2Lo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=SodCQ8b2uZA:rjibrpXB2Lo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=SodCQ8b2uZA:rjibrpXB2Lo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=SodCQ8b2uZA:rjibrpXB2Lo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=SodCQ8b2uZA:rjibrpXB2Lo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/SodCQ8b2uZA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/reconciling-yagni-with-reversibility</feedburner:origLink></entry>
 
 <entry>
   <title>AI Application Programming - Book Review</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/voCozGDYLN8/ai-application-programming-book-review" />
   <updated>2009-01-18T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/ai-application-programming-book-review</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m spending a lot of my time lately reading about AI, both game related, business application related and academia related. Having recently completed &amp;#8220;&lt;em&gt;AI Application Programming&lt;/em&gt;&amp;#8221; by M. Tim Jones (Charles River Media, 2003, First Edition), I have decided to review it in the context of my current situation.&lt;/p&gt;
&lt;p&gt;I am new to the field of AI, and my previous reading has been limited to sporadic Wikipedia research on concepts as I come across them. This book covers a lot of material that I haven&amp;#8217;t read about before, but it also covers some material I have. This allows me to evaluate the book as both someone with prior knowledge, and someone with no knowledge.&lt;/p&gt;
&lt;p&gt;Firstly, the book was a fairly broad overview on integrating aspects of artificial intelligence into application development. Therefore it was no surprise that a majority of the AI concepts discussed were optimization oriented. The book provided an overview of the history of AI, then it covered simulated annealing, adaptive resonance theory, ant algorithms/ant colony optimization, neural networks, genetic algorithms, a chapter on using some of the techniques described to run artificial life simulations, rules based systems, fuzzy logic, bigrams/Markov chains, agent based software and a wrap up the future of AI.&lt;/p&gt;
&lt;p&gt;Each chapter is fairly formulaic. It starts with an overview of the theory of the subject for that chapter, and the presentation of any relevant formula. Then a basic example is covered, without code, in order to show how the theory being covered can be applied. Then a specific example with C source is covered, with a detailed explanation of what&amp;#8217;s going on. I largely glossed over the source, as I don&amp;#8217;t really have much familiarity with C, so cannot comment on the quality of the source.&lt;/p&gt;
&lt;p&gt;Overall I have mixed feelings about the book. A lot of the topics have domain specific language, such as referring to parts of algorithms as genes and candidate algorithms as chromosomes in genetic algorithms, and I feel the author sticks to these to the detriment of comprehension of the topic. For example, the author was discussing &amp;#8220;energy&amp;#8221; and &amp;#8220;temperature&amp;#8221; with relation to simulated annealing, without outlining that it&amp;#8217;s goal was to narrow the search space for a solution to a  given problem.&lt;/p&gt;
&lt;p&gt;Another detracting factor was the numerous errors in diagrams, equations and the text. These errors can be attributed to a variety of sources, from poor copying jobs on some of the diagrams to bad editing. One particularly annoying error was the diagram showing how a &lt;span class="caps"&gt;NOT&lt;/span&gt; logic gate could be constructed using a single neuron neural network &amp;#8211; the diagram showed an input bias of 1, with a weight of 1 on the input, claiming that the output will always be the inverse of the input, by the equation &lt;em&gt;output = input * input weight + bias&lt;/em&gt;.&lt;br /&gt;
An input of 0 into this equation will indeed output a 1, however an input 1 will yield 2, which is incorrect. The correct diagram should have a input weight of -1, which will yield a correct answer with both the 0 and 1 inputs. These errors hindered the understanding of the topic.&lt;/p&gt;
&lt;p&gt;However, it&amp;#8217;s not all bad news. From my personal reading, I had always struggled with how the back propagation algorithm in neural networks worked, and this book managed to successfully explain it. A lot of the other topics, such as fuzzy logic and the rules based system were also well presented and relatively straight forward.&lt;/p&gt;
&lt;p&gt;From reading this book, I feel I have a solid enough understanding of the basics of the topics covered that I could successfully go out and perform my own, more in depth research and succeed fairly well, as well as integrate a few of the more rudimentary features of these approaches into an application.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=voCozGDYLN8:I8OtzWN3xd4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=voCozGDYLN8:I8OtzWN3xd4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=voCozGDYLN8:I8OtzWN3xd4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=voCozGDYLN8:I8OtzWN3xd4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=voCozGDYLN8:I8OtzWN3xd4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=voCozGDYLN8:I8OtzWN3xd4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=voCozGDYLN8:I8OtzWN3xd4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/voCozGDYLN8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/ai-application-programming-book-review</feedburner:origLink></entry>
 
 <entry>
   <title>How To Run Your Own Webserver</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/eT3kjQZZ6w4/how-to-run-your-own-webserver" />
   <updated>2009-01-14T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/how-to-run-your-own-webserver</id>
   <content type="html">&lt;p&gt;For some time, I&amp;#8217;ve run my own web server from the comfort of my own home. I made this decision due to the fact that I wanted more control over my server, and I wanted to run as many web development languages side by side as I could, and mainly because I wanted to run &lt;span class="caps"&gt;SVN&lt;/span&gt;. Before I started hosting my own websites, I had a sketchy knowledge of how the &lt;span class="caps"&gt;DNS&lt;/span&gt; works, and how to go about hosting your own websites on a Linux operating system. I also had minimal Linux administration skills.&lt;/p&gt;
&lt;p&gt;There are a few good reasons for hosting your own website:&lt;br /&gt;
&lt;ol&gt;&lt;br /&gt;
	&lt;li&gt;No artificial caps on bandwidth and hard disk usage. You pay for what you use, and if you need more, you buy more.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;Total control over your hosting environment. If you want a language installed, install it. If you want to run a certain version of Rails, run it. It&amp;#8217;s your server.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;Experience. Hosting your own websites on your own server can give you a lot of experience with systems administration on a server operating system.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;Cost. You have complete control over how much everything costs, and you know exactly where your money is going. You can spend as much or as little as you wanted.&lt;/li&gt;&lt;/p&gt;
&lt;/ol&gt;
&lt;h3&gt;How Do You Do It?&lt;/h3&gt;
&lt;p&gt;First, it helps to get an idea of what you really want. Do you want to run a huge corporate intranet with load balancing and proxy servers, or do you just want a small server to host personal sites and tinker? Is your budget limitless, or are you already living on ramen for dinner 5 nights a week? Do you want to host proprietary languages like Cold Fusion or &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt;, or will a Linux/Apache install satisfy you?&lt;/p&gt;
&lt;p&gt;Personally, I was only interested in hosting personal sites, and doing it cheaply was my utmost concern. This is what I will focus on, as this is what I have experience in. So, what I was looking for was a relatively easy solution that was above all cheap.&lt;br /&gt;
&lt;h3&gt;1. Get Your Hardware&lt;/h3&gt;&lt;br /&gt;
Before you can start, you need to have hardware to put your server on, and if you already don&amp;#8217;t have it, appropriate networking gear to support multiple computers accessing the same internet connection (if you want to use a personal computer as well).&lt;/p&gt;
&lt;p&gt;As your end goal is a web server, this server preferably needs to be up 24/7, which means whatever hardware you choose to run it on will essentially cease to exist with regards to usage. Most of the time, hopefully, you&amp;#8217;ll never need to do much work on the server itself, only transferring data to and from it.&lt;/p&gt;
&lt;p&gt;I already had my networking gear, and I commandeered an old desktop computer for my server. It was a Pentium IV 3.0GHz with 2GB of &lt;span class="caps"&gt;RAM&lt;/span&gt;. I found in the year or so I ran the server that my memory usage didn&amp;#8217;t ever go above ~400mb. I also had a 120GB hard disk in there. This computer used to serve as my old gaming workstation, however I don&amp;#8217;t play games much these days, and I bought a laptop that was more powerful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost: &lt;/strong&gt;Free&lt;br /&gt;
&lt;h3&gt;2. Get Your Software&lt;/h3&gt;&lt;br /&gt;
I chose to run CentOS 5 as my Linux distribution. My choice was admittedly relatively arbitrary, however I was relatively happy with the choice. I installed the OS and included only the packages that I knew I needed &amp;#8211; that meant no xserver, and no &lt;span class="caps"&gt;GUI&lt;/span&gt;. I was going to administrate this server via ssh on my laptop. I then updated the OS and installed all the required software.&lt;/p&gt;
&lt;p&gt;I immediately recognised that it would be hard to individually install and hook up everything that I wanted to run, and decided to run a web-server software package to help. I eventually settled on Webmin after a few false starts, and Webmin proved to be very user friendly and relatively powerful. If I was doing the same thing again, I would be relatively comfortable doing it all individually without Webmin, but it was Webmin that provided me with a safety net while learning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost: &lt;/strong&gt;Free&lt;br /&gt;
&lt;h3&gt;3. Get Connected&lt;/h3&gt;&lt;br /&gt;
I was already running the biggest Internet providing plan that my &lt;span class="caps"&gt;ISP&lt;/span&gt; offered. As I live in Australia, we have to live with usage caps on our Internet plans. Mine was 20GB download during peak traffic, 40GB download during off-peak, and unmetered upload. This was perfect for hosting a server, as most of my traffic was upload, once I got everything installed.&lt;/p&gt;
&lt;p&gt;However, you do need more than just an Internet connection to get a server online, you also need a static IP address. Technically you can do it with a dynamic IP and a dynamic &lt;span class="caps"&gt;DNS&lt;/span&gt; service, however that was a level of complexity I didn&amp;#8217;t have the patience to deal with. So I put a static IP on my account as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost: &lt;/strong&gt;$10/month for the static IP, Internet was free because I was using the connection anyway&lt;br /&gt;
&lt;h3&gt;4. Get Hosted&lt;/h3&gt;&lt;br /&gt;
This is the final step to getting your server ready to host websites. So far, you have a server with the software installed, and you have an Internet connection and a static IP. You can type your static IP in a browser and get your Webmin&amp;#8217;s default landing page (if your router supports &lt;span class="caps"&gt;NAT&lt;/span&gt;  loopback, which mine didn&amp;#8217;t). To get your web server attached to a domain name, you first must register the domain name, then point it to nameservers that run a &lt;span class="caps"&gt;DNS&lt;/span&gt; server. &lt;/p&gt;
&lt;p&gt;You could run the &lt;span class="caps"&gt;DNS&lt;/span&gt; server on the same machine, or a different machine, but that was all too complicated for me. I instead chose to get a hosted &lt;span class="caps"&gt;DNS&lt;/span&gt; solution with Nettica, and have Nettica manage my name servers. Then it was simply a matter of pointing my domains to the Nettica nameservers, pointing my Nettica entries to my server IP, and add the virtual servers with Webmin, letting it take care of configuring Apache for named virtual hosting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost: &lt;/strong&gt;$50/year&lt;/p&gt;
&lt;p&gt;So that&amp;#8217;s it. For about $170/year, I could host my own server and serve as many websites as I had room for on the Internet. I had complete control over the server, and I could install what I wanted, when I wanted.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t run the server now, as I have recently moved to a location where I cannot justify it, but overall I found the experience very rewarding. Sure, you can get cheaper shared hosting, but there&amp;#8217;s nothing like deciding you want to install, say, &lt;span class="caps"&gt;SVN&lt;/span&gt; and just installing it, and having it up and ready in 10 minutes for no charge.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eT3kjQZZ6w4:AI-cXqmBwLA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eT3kjQZZ6w4:AI-cXqmBwLA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=eT3kjQZZ6w4:AI-cXqmBwLA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eT3kjQZZ6w4:AI-cXqmBwLA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=eT3kjQZZ6w4:AI-cXqmBwLA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eT3kjQZZ6w4:AI-cXqmBwLA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=eT3kjQZZ6w4:AI-cXqmBwLA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/eT3kjQZZ6w4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/how-to-run-your-own-webserver</feedburner:origLink></entry>
 
 <entry>
   <title>PHP Has An Identity Crisis</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/K3ibjxjdwJE/php-has-an-identity-crisis" />
   <updated>2009-01-11T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/php-has-an-identity-crisis</id>
   <content type="html">&lt;p&gt;I have been using &lt;span class="caps"&gt;PHP&lt;/span&gt; for quie a while. I first learnt &lt;span class="caps"&gt;PHP&lt;/span&gt; 4 when I was 18-19, building a dynamic art gallery type site for my drawing attempts. I thought it was wonderful that I could programmatically display new images without having to update the &lt;span class="caps"&gt;HTML&lt;/span&gt; file. I also used &lt;span class="caps"&gt;PHP&lt;/span&gt; for my final year project in university, and by the time I graduated, I was quite proficient in it.&lt;/p&gt;
&lt;p&gt;However, as I slowly got more and more interested in programming, and the principles of programming, I learn more and more languages, and learnt &lt;span class="caps"&gt;OOP&lt;/span&gt; practices that I never applied to &lt;span class="caps"&gt;PHP&lt;/span&gt;, simply because I was self taught, and at the time &lt;span class="caps"&gt;PHP&lt;/span&gt; wasn&amp;#8217;t pushing itself as an &lt;span class="caps"&gt;OOP&lt;/span&gt; language.&lt;/p&gt;
&lt;p&gt;However, times change, and the &lt;span class="caps"&gt;PHP&lt;/span&gt; community tends to push the fact that &lt;span class="caps"&gt;PHP&lt;/span&gt; is an &lt;span class="caps"&gt;OOP&lt;/span&gt; language. Firstly, this isn&amp;#8217;t entirely accurate. &lt;span class="caps"&gt;PHP&lt;/span&gt; is a language that supports &lt;span class="caps"&gt;OOP&lt;/span&gt;, however it isn&amp;#8217;t an &lt;span class="caps"&gt;OOP&lt;/span&gt; language. There is no string object &amp;#8211; I cannot take a substring of a string by calling a method on the string variable. Instead I must use a global function substr() to do it. That&amp;#8217;s not &lt;span class="caps"&gt;OOP&lt;/span&gt;, it&amp;#8217;s procedural wrapped in &lt;span class="caps"&gt;OOP&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;However, &lt;span class="caps"&gt;PHP&lt;/span&gt; does support &lt;span class="caps"&gt;OOP&lt;/span&gt;. You can define custom classes, you can create objects and you can call methods on that object. In a hostile world full of more &lt;span class="caps"&gt;OOP&lt;/span&gt; languages like Ruby and Python that are gaining traction in the web development world, &lt;span class="caps"&gt;PHP&lt;/span&gt; must push more and more it&amp;#8217;s &lt;span class="caps"&gt;OOP&lt;/span&gt; support. If you talk with serious developers in the world of &lt;span class="caps"&gt;PHP&lt;/span&gt;, they will insist that although &lt;span class="caps"&gt;PHP&lt;/span&gt; is not inherently an &lt;span class="caps"&gt;OOP&lt;/span&gt; language, it&amp;#8217;s close enough.&lt;/p&gt;
&lt;p&gt;Today I found out that from &lt;span class="caps"&gt;PHP&lt;/span&gt; has &lt;a title="GOO at PHP.net" href="http://uk3.php.net/manual/en/control-structures.goto.php"&gt;introduced in &lt;span class="caps"&gt;PHP&lt;/span&gt; 5.3 the &lt;span class="caps"&gt;GOTO&lt;/span&gt; statement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For those of you who are unaware of the specifics of the &lt;span class="caps"&gt;GOTO&lt;/span&gt; function, &lt;a href="http://phpimpact.wordpress.com/2009/01/08/php-spaghetti-alla-bolognese/"&gt;this post&lt;/a&gt;, also the post that I learnt this fact from, outlines it. While experienced programmers know enough to avoid the &lt;span class="caps"&gt;GOTO&lt;/span&gt; statement, new programmers may not, and &lt;span class="caps"&gt;PHP&lt;/span&gt; can be abused enough already without the &lt;span class="caps"&gt;GOTO&lt;/span&gt; statement.&lt;/p&gt;
&lt;p&gt;So, what is it &lt;span class="caps"&gt;PHP&lt;/span&gt;? Are you an &lt;span class="caps"&gt;OOP&lt;/span&gt; language, or are you procedural? The &lt;span class="caps"&gt;PHP&lt;/span&gt; community pushes it&amp;#8217;s support for &lt;span class="caps"&gt;OOP&lt;/span&gt;, and then it introduces a control statement that characterises the worst of procedural code. &lt;span class="caps"&gt;PHP&lt;/span&gt; needs to clarify it&amp;#8217;s future as a language, and decide whether to push itself as an &lt;span class="caps"&gt;OOP&lt;/span&gt; language or as a procedural language.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=K3ibjxjdwJE:O4bhdo-3d_0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=K3ibjxjdwJE:O4bhdo-3d_0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=K3ibjxjdwJE:O4bhdo-3d_0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=K3ibjxjdwJE:O4bhdo-3d_0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=K3ibjxjdwJE:O4bhdo-3d_0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=K3ibjxjdwJE:O4bhdo-3d_0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=K3ibjxjdwJE:O4bhdo-3d_0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/K3ibjxjdwJE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/php-has-an-identity-crisis</feedburner:origLink></entry>
 
 <entry>
   <title>Encapsulation in Python</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/a9pexR6XQSA/encapsulation-in-python" />
   <updated>2009-01-03T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/encapsulation-in-python</id>
   <content type="html">&lt;p&gt;Or, &amp;#8220;I see London, I see France, I see Python&amp;#8217;s underpants&amp;#8221;&lt;/p&gt;
&lt;p&gt;I come from a primarily C# background, where I have fairly tight control over how visible my properties and methods are. I can choose to make them private to the class, protected to the class and it&amp;#8217;s children, internal to the assembly or public for everything.&lt;/p&gt;
&lt;p&gt;In my course of learning Python, I&amp;#8217;ve discovered awesome things like docstrings, multiple inheritance and sequence unpacking. However, I&amp;#8217;ve also been shocked and made more than a little uncomfortable by the realisation that Python doesn&amp;#8217;t implement encapsulation. I don&amp;#8217;t trust other people not to abuse access to methods that I&amp;#8217;ve intended to be private &amp;#8211; I&amp;#8217;ve seen too much bad code for that. While I know &lt;a title="Encapsulation in Python" href="http://importantshock.wordpress.com/2006/11/03/adventures-in-pythonic-encapsulation/"&gt;there are ways to get around this&lt;/a&gt;, I don&amp;#8217;t feel I should have to perform code gymnastics to implement what I feel is an essential part of an OO language.&lt;/p&gt;
&lt;p&gt;Another thing that makes me cringe a little about Python is the need to pass in the self parameter for all object methods. I realise that this is required to differentiate between an instance method and a class/static method, however I just can&amp;#8217;t shake the idea that it seems a little clunky, even though I know it&amp;#8217;s no different from writing a static at the start of my function definition.&lt;/p&gt;
&lt;p&gt;However, to wrap up the last two weeks, I feel confident in saying that from what I&amp;#8217;ve seen I like Ruby more than I like Python. That&amp;#8217;s not to say these are bad languages; I first learnt web based programming with &lt;span class="caps"&gt;PHP&lt;/span&gt;, and I&amp;#8217;m sure that I&amp;#8217;m going to leave &lt;span class="caps"&gt;PHP&lt;/span&gt; in the dust for one of these two languages. I will also disclose that I did not learn Python 3.0, and haven&amp;#8217;t really looked into it whatsoever, so if 3.0 changes some of the stuff here, forgive me.&lt;/p&gt;
&lt;p&gt;Having said that, I will investigate both languages more, and definitely work in both more. I&amp;#8217;ve found &lt;span class="caps"&gt;PHP&lt;/span&gt; doesn&amp;#8217;t do it for me anymore, I&amp;#8217;ve seen a better side of programming where I don&amp;#8217;t have to live with ugly warts in my languages, and &lt;span class="caps"&gt;PHP&lt;/span&gt; is ugly. Long live Python and Ruby.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=a9pexR6XQSA:jZ21ITW-iSc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=a9pexR6XQSA:jZ21ITW-iSc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=a9pexR6XQSA:jZ21ITW-iSc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=a9pexR6XQSA:jZ21ITW-iSc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=a9pexR6XQSA:jZ21ITW-iSc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=a9pexR6XQSA:jZ21ITW-iSc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=a9pexR6XQSA:jZ21ITW-iSc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/a9pexR6XQSA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/encapsulation-in-python</feedburner:origLink></entry>
 
 <entry>
   <title>Don't Get the Wrong Degree</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/ECcINjl-Urg/dont-get-the-wrong-degree" />
   <updated>2009-01-03T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/dont-get-the-wrong-degree</id>
   <content type="html">&lt;p&gt;I recently read an &lt;a title="Relevance of CS degree - Daniel Pratt" href="http://www.danielgpratt.com/2009/01/confession-i-dont-have-degree.html"&gt;interesting post&lt;/a&gt; that popped up in my feed reeder on Saturday night, on a subject that strikes &lt;a title="Learning Mathematics - Tim Gittos" href="http://www.timgittos.com/learning-mathematics"&gt;very close to home&lt;/a&gt;. Obviously I am not in the exact same situation; I have a degree.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But I have the wrong degree.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Software Engineering degree I studied was very heavy on the management side of software engineering, and light on the actual implementation side of programming. I don&amp;#8217;t know if this is common to SE degrees, however I found this was the case with mine.&lt;/p&gt;
&lt;p&gt;I share Daniel&amp;#8217;s love and thirst for information, and have a very strong drive to learn as much about everything as I can. So, on the surface, the dilemma of not having the right degree seems fairly harmless. Daniel describes the phenomena of &amp;#8220;perception is reality&amp;#8221; &amp;#8211; people perceive that having a degree is better than not having a degree. So I guess I have a head start in that aspect. I have the piece of paper, I don&amp;#8217;t have to deal with these negative perceptions.&lt;/p&gt;
&lt;p&gt;Instead, I had to deal with the mistaken belief that I was more competent than I was.&lt;/p&gt;
&lt;p&gt;I have never worked in a large company. The company I&amp;#8217;m with now is the largest company I&amp;#8217;ve ever been with, and we only have 4 developers, including myself. I&amp;#8217;ve always worked with smaller companies, that either only dabble in programming, or were start-ups. It wasn&amp;#8217;t until I looked at a job posting at a larger company that I realised that I may have made a huge, 3 year long mistake.&lt;/p&gt;
&lt;p&gt;The job posting was your standard outline of positional requirements and expected experience and education, but it also had a puzzle attached. You had to complete the puzzle, in your language of choice, and submit the code along with your resume for consideration. This was in late 2006. I can say now that it was a simple graph problem, finding the minimal spanning tree of any given graph. Back then, however, I thought it was just an odd puzzle.&lt;/p&gt;
&lt;p&gt;I didn&amp;#8217;t know this was a class of problem. I didn&amp;#8217;t know this was rooted in mathematical theory, I didn&amp;#8217;t know there were algorithms for solving this. I charged head first into solving the puzzle blindly. I ended up with a 90% complete solution that came very close to &lt;a title="Prim's Algorithm - Wikipedia" href="http://en.wikipedia.org/wiki/Prim%27s_algorithm"&gt;Prim&amp;#8217;s algorithm&lt;/a&gt;. I submitted my crippled solution, and naturally didn&amp;#8217;t get the position. Later, someone pointed out what class of problem it was, and I was off searching for it.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s when it hit me.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s when I found out how little I knew about my craft.&lt;/p&gt;
&lt;p&gt;Since that day, I&amp;#8217;ve regretted every year in that software engineering degree, every year I learnt things that I wasn&amp;#8217;t interested in (management) that I could have spent doing computer science. If I could afford it, and if I could afford the time off, I would go back, start fresh and do a computer science degree. However, the more I learn, the more this desire fades. But there is not a day that I do not strive to fill the gaps in my knowledge myself.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not bashing Software Engineering. I know it was my fault for not properly researching the course material offered, I know that I could have gotten what I missed from another institution. The only reason I know this, however, is because I learnt enough about the industry to know what I was missing, and subsequently, know what I needed. And that&amp;#8217;s not something every potential high school graduate looking to get into programming will know.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not enough to get a degree &amp;#8211; you have to make sure you get the right degree, from the right place. Unfortunately, that generally takes more experience to judge than you have right out of high-school.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=ECcINjl-Urg:hONY4TqMzOg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=ECcINjl-Urg:hONY4TqMzOg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=ECcINjl-Urg:hONY4TqMzOg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=ECcINjl-Urg:hONY4TqMzOg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=ECcINjl-Urg:hONY4TqMzOg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=ECcINjl-Urg:hONY4TqMzOg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=ECcINjl-Urg:hONY4TqMzOg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/ECcINjl-Urg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/dont-get-the-wrong-degree</feedburner:origLink></entry>
 
 <entry>
   <title>Passing Parameters in Actionscript</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/oD0pBKElcKM/passing-parameters-in-actionscript" />
   <updated>2008-12-28T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/passing-parameters-in-actionscript</id>
   <content type="html">&lt;p&gt;While in the process of trying to learn Python, I decided it would be a good idea to attempt to learn some AI and AI related concepts at the same time using the PyGame framework, as advised by &lt;a title="Getting Started in AI - AIGameDev" href="http://aigamedev.com/questions/starting-programming"&gt;AIGameDev&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For a while, I&amp;#8217;ve had this really nice &lt;a title="Steering Behaviors for Autonomous Characters" href="http://www.red3d.com/cwr/steer/"&gt;steering demo/white paper&lt;/a&gt; in my &lt;a title="My Delicious bookmarks" href="http://www.delicious.com/summaro"&gt;Delicious&lt;/a&gt; account, something that I&amp;#8217;ve meant to try implementing myself. Because this was entirely new territory, and I know my physics/math isn&amp;#8217;t up to scratch, I decided to try to implement some of the behaviors outlined in the previous paper in Actionscript 3.0 first, then when I got the hang of it, port it to Python.&lt;/p&gt;
&lt;p&gt;After about 8 hours or so, I had finally puzzled out the seek/flee behavior, and tried to put together a demo as in the above page, when I hit a strange bug. If I put the seek behavior vehicle on the stage on it&amp;#8217;s own, it performed correctly. If I placed the flee behavior vehicle on the stage on it&amp;#8217;s own, it performed correctly. If I had both on the stage at once, they freaked out and opposed one another, and the two vehicles often got caught in a state of equilibrium, their velocities canceling each other out.&lt;/p&gt;
&lt;p&gt;It seemed as if my little vehicle views were sharing the same vehicle model, and the two different behaviors were acting on the same vehicle model. Which didn&amp;#8217;t make any sense, considering they were two separate instances of the same class.&lt;/p&gt;
&lt;p&gt;After a lot of bug testing and fiddling around, I finally realise I had been caught by the way Actionscript passes parameters into functions/constructors: &lt;strong&gt;unless you&amp;#8217;re passing a primitive data type, Actionscript passes by reference&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I was instantiating my vehicles with the same velocity and starting position, and I was using arrays to pass in this information into the constructors, little knowing that the actual array each class &lt;em&gt;was manipulating was the same array&lt;/em&gt;.&lt;br /&gt;
You can easily bypass this by importing&lt;br /&gt;
&lt;pre&gt;mx.utils.ObjectUtil&lt;/pre&gt;&lt;br /&gt;
and using the&lt;br /&gt;
&lt;pre&gt;ObjectUtil.copy&lt;/pre&gt;&lt;br /&gt;
method (remembering to cast it back to your desired data type, in my case an array).&lt;br /&gt;
So, if you find your instances seem to be sharing private variables they shouldn&amp;#8217;t be, check your parameters and make sure you&amp;#8217;re not passing things by reference to multiple instances and manipulating them.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oD0pBKElcKM:9O-vXmFzvRE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oD0pBKElcKM:9O-vXmFzvRE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=oD0pBKElcKM:9O-vXmFzvRE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oD0pBKElcKM:9O-vXmFzvRE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=oD0pBKElcKM:9O-vXmFzvRE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=oD0pBKElcKM:9O-vXmFzvRE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=oD0pBKElcKM:9O-vXmFzvRE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/oD0pBKElcKM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/passing-parameters-in-actionscript</feedburner:origLink></entry>
 
 <entry>
   <title>Ruby Wrap Up</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/ptWir-c5PNM/ruby-wrap-up" />
   <updated>2008-12-25T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/ruby-wrap-up</id>
   <content type="html">&lt;p&gt;Today marks the last day of my Ruby portion of my Ruby/Python Bootcamp. Unfortunately with the Christmas and related Christmas stresses, and an impending move, I didn&amp;#8217;t get to spend a lot of time with the language, beyond the fundamentals.&lt;/p&gt;
&lt;p&gt;I did a dumb thing, and started to try to get a website up and going on Rails 2.2. Rails is a great framework, although I&amp;#8217;ve found the learning curve beyond your basic scaffolding and &lt;span class="caps"&gt;MVC&lt;/span&gt; set up to be fairly high. I made extensive use of&lt;a title="Rails 2.2 API Dictionary" href="http://www.railsbrain.com/api/rails-2.2.2/doc/index.html"&gt; this Rails &lt;span class="caps"&gt;API&lt;/span&gt; guide&lt;/a&gt; and it certainly helped a lot, as did &lt;a title="Ruby on Rails Guides portal" href="http://guides.rubyonrails.org/"&gt;the Ruby on Rails guides portal&lt;/a&gt;. The reason this was as dumb idea had nothing to do with Rails or Ruby, and everything to do with the fact &lt;a title="Why I don't like making websites - timgittos.com" href="http://www.timgittos.com/wordpress-or-roll-your-own"&gt;I hate making websites&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Seriously, I&amp;#8217;m on holiday. I should be staying away from websites for a while.&lt;/p&gt;
&lt;p&gt;So, I didn&amp;#8217;t end up doing much on the website I promised I&amp;#8217;d show, and there&amp;#8217;s not really anything to show, yet. I did manage to set up an excellent workflow with &lt;span class="caps"&gt;SVN&lt;/span&gt; and my web-host, which will eliminate the need for an &lt;span class="caps"&gt;FTP&lt;/span&gt; client, and Ruby did help me complete my partial understanding of RESTful design.&lt;/p&gt;
&lt;p&gt;So, I walk away after a week of Ruby with a rudimentary knowledge of Ruby syntax, which is enough to let me read Ruby code and fill in the gaps myself, a stronger knowledge of RESTful design and a much smarter development workflow.&lt;/p&gt;
&lt;p&gt;Thanks, Ruby.&lt;/p&gt;
&lt;p&gt;So, tomorrow, or tonight, I&amp;#8217;ll kick off Python, and I&amp;#8217;ll also see if I can&amp;#8217;t use it while investigating a few other programming related interests, like OpenGL programming or some AI stuff, if I can figure it out. Hopefully I&amp;#8217;ll be able to get as much out of Python as I got out of Ruby.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=ptWir-c5PNM:LwJ-J1QOF3Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=ptWir-c5PNM:LwJ-J1QOF3Q:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=ptWir-c5PNM:LwJ-J1QOF3Q:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=ptWir-c5PNM:LwJ-J1QOF3Q:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=ptWir-c5PNM:LwJ-J1QOF3Q:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=ptWir-c5PNM:LwJ-J1QOF3Q:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=ptWir-c5PNM:LwJ-J1QOF3Q:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/ptWir-c5PNM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/ruby-wrap-up</feedburner:origLink></entry>
 
 <entry>
   <title>First Impressions Of Ruby</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/WV6_X341Y8c/first-impressions-of-ruby" />
   <updated>2008-12-20T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/first-impressions-of-ruby</id>
   <content type="html">&lt;p&gt;I like it.&lt;/p&gt;
&lt;p&gt;A lot.&lt;/p&gt;
&lt;p&gt;But I always knew I would. I&amp;#8217;m so far impressed with how much effort Ruby goes to at making itself understood at a casual glance, and just how easy it is to write self documenting code. Writing code that&amp;#8217;s free of braces and parenthesis is refreshing, and it&amp;#8217;s nice to know the safety blanket is there (with regards to parenthesis for functions, conditional statements, etc) is there if I need it.&lt;/p&gt;
&lt;p&gt;I started last night by flicking through &lt;a title="Why's (Poingant) Guide to Ruby" href="http://poignantguide.net/ruby/"&gt;Why&amp;#8217;s (Poignant) Guide&lt;/a&gt;, and found it pretty good for the basics. I quickly picked up the general concepts and basic syntax fast, and Why&amp;#8217;s Guide was pretty whimsical and kept things interesting. However I quickly bored of the absurdity in chapter 5 where the majority of its content is fluff.&lt;/p&gt;
&lt;p&gt;I tried switching to &lt;a title="The Book of Ruby" href="http://www.sapphiresteel.com/The-Book-Of-Ruby"&gt;SaphireSteel&amp;#8217;s The Book of Ruby&lt;/a&gt;, however right at the start when the author stated:&lt;br /&gt;
&lt;blockquote&gt;if (subtotal &amp;lt; 0.0) then subtotal = 0.0 end&lt;/p&gt;
&lt;p&gt;Putting everything on one line like this adds nothing to the clarity of the code, which is why I prefer to avoid it&lt;/blockquote&gt;&lt;br /&gt;
I knew that this book would not help me. I already know many languages that require simple statements like that to be spread over multiple lines. I want a language to do this:&lt;/p&gt;
&lt;p&gt;[code language=&amp;#8220;ruby&amp;#8221;]subtotal = 0.0 if subtotal &amp;lt; 0.0[/code]&lt;/p&gt;
&lt;p&gt;Hi, Ruby.&lt;/p&gt;
&lt;p&gt;Then I browsed over to &lt;a title="Ruby in 20 Minutes" href="http://www.ruby-lang.org/en/documentation/quickstart/"&gt;Ruby in 20 Minutes&lt;/a&gt; and quickly flicked through the pages, and it concreted my knowledge. I like iterators, I like respond_to?, I like how everything seems to make sense. I also am pleased to see how many concepts map onto similar things in C#. Modules are like namespaces, but better. attr_accessor is like { get; set;}. attr_reader is like {get; private set;}.&lt;/p&gt;
&lt;p&gt;I feel I&amp;#8217;m ready to go find some code in the wild and attempt to read it. I&amp;#8217;ll also see if I can come up with a post that maps Ruby concepts to C# concepts for other C# programmers interested in Ruby (and with IronRuby, there&amp;#8217;s no reason why you shouldn&amp;#8217;t be).&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=WV6_X341Y8c:L4AzM31joRk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=WV6_X341Y8c:L4AzM31joRk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=WV6_X341Y8c:L4AzM31joRk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=WV6_X341Y8c:L4AzM31joRk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=WV6_X341Y8c:L4AzM31joRk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=WV6_X341Y8c:L4AzM31joRk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=WV6_X341Y8c:L4AzM31joRk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/WV6_X341Y8c" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/first-impressions-of-ruby</feedburner:origLink></entry>
 
 <entry>
   <title>Ruby &amp; Python Bootcamp</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/zmgUEWnAFW4/ruby-python-bootcamp" />
   <updated>2008-12-19T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/ruby-python-bootcamp</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s common advice in the programming industry to learn one new language every year to stay on top of things. It&amp;#8217;s something I honestly believe in as well. Unfortunately I can&amp;#8217;t say I&amp;#8217;ve learnt a new language this year.&lt;/p&gt;
&lt;p&gt;Last year, I learnt Actionscript 3.0, which is different enough from Actionscript 2.0 to be called a new language. I did this because of work, I did it in December and I had to do it &lt;strong&gt;&lt;em&gt;fast&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;.&lt;/em&gt; That worked pretty well for me. I got thrown in the deep end and had to learn or drown.&lt;/p&gt;
&lt;p&gt;This year, with this being my last day at work for 2 weeks, I&amp;#8217;m going to do the same thing, but I&amp;#8217;m going to make it a little more interesting. I consider myself a reasonably competent programmer, and fairly solid in my knowledge of &lt;span class="caps"&gt;OOP&lt;/span&gt; paradigms. I think I can learn a language pretty quick. So, during my holidays, I&amp;#8217;m going to:&lt;br /&gt;
&lt;ol&gt;&lt;br /&gt;
	&lt;li&gt;See how fast I really can learn a language at least to the point where I know what to search for online and can find my own way around reasonably confidently.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;See just how easily various concepts from different languages transfer across syntax&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;Build some stuff I&amp;#8217;ve been meaning to build for a while but kept putting off&lt;/li&gt;&lt;/p&gt;
&lt;/ol&gt;
&lt;p&gt;With that in mind, this year I&amp;#8217;m going to learn both &lt;strong&gt;Ruby and Python in 2 weeks&lt;/strong&gt;, dedicating a week to both languages. In the process of learning these languages, I will also build a base for 2 websites for 2 of my domains that I have been meaning to build. I won&amp;#8217;t spend any time designing them, just building the code.&lt;/p&gt;
&lt;p&gt;So, over the next 2 weeks, the majority of posts on here will be reflecting my thoughts on Ruby and Python, and linking to resources that I plan to use in my learning, with a final post being the unveiling of the websites I manage to build.&lt;/p&gt;
&lt;p&gt;Wish me luck!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=zmgUEWnAFW4:HiYzRUfR7yQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=zmgUEWnAFW4:HiYzRUfR7yQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=zmgUEWnAFW4:HiYzRUfR7yQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=zmgUEWnAFW4:HiYzRUfR7yQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=zmgUEWnAFW4:HiYzRUfR7yQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=zmgUEWnAFW4:HiYzRUfR7yQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=zmgUEWnAFW4:HiYzRUfR7yQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/zmgUEWnAFW4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/ruby-python-bootcamp</feedburner:origLink></entry>
 
 <entry>
   <title>Wireframe Your Interfaces First</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/JTbn-Jdq-m4/wireframe-your-interfaces-first" />
   <updated>2008-12-17T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/wireframe-your-interfaces-first</id>
   <content type="html">&lt;p&gt;As I&amp;#8217;ve mentioned in &lt;a title="Compile an .ascx as a .dll - timgittos.com" href="http://www.timgittos.com/compile-a-user-control-as-a-dll"&gt;a past post&lt;/a&gt;, I&amp;#8217;m doing a rebuild of the &lt;acronym title="Content Management System"&gt;&lt;span class="caps"&gt;CMS&lt;/span&gt;&lt;/acronym&gt; here at work and I&amp;#8217;ve reached the point where the internals are done, and now I have to create a user interface for the application.&lt;/p&gt;
&lt;p&gt;Now, in the past I have worked a variety of jobs and in those jobs a variety of roles. One of my jobs saw me as a web developer, like now, but with a difference: I was the &lt;strong&gt;only&lt;/strong&gt; web developer.&lt;/p&gt;
&lt;p&gt;I was responsible for quoting, requirements analysis, planning, design, development, testing, debugging, deployment and maintenance. If there&amp;#8217;s only one thing I learned there, it was that web development is more than &lt;span class="caps"&gt;HTML&lt;/span&gt; and Javascript and a server side language, and a freelance web developer needs to know &lt;em&gt;more&lt;/em&gt; than just programming and design.&lt;/p&gt;
&lt;p&gt;What I really found hard was the design part.&lt;/p&gt;
&lt;p&gt;That is, until I read somewhere that design is visual communication. Just like any other form of communication, you need to have a point, something to say. However, that point can very easily get lost in the minutiae of designing, of making sure something looks good.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve found that wireframing is essential. You use the wireframe to establish the &lt;em&gt;point&lt;/em&gt; of the page, the information that a page needs to contain, free of it&amp;#8217;s appearance. You use the wireframe to tweak the structure, to experiment with different work flows. When you&amp;#8217;re done, you go over the top and start designing.&lt;/p&gt;
&lt;p&gt;Wireframing has enabled me to quickly build a general structure for a user interface, concentrating on the information and tasks that interface needs to perform.&lt;/p&gt;
&lt;p&gt;I &lt;a title="Balsamiq - Wireframe and mockup tool" href="http://www.balsamiq.com/"&gt;wireframe with Balsamiq&lt;/a&gt;, which I&amp;#8217;ve found to be an excellent tool. You can try it out indefinitely on their site, fully functional, and all it costs is pop-up every 5 minutes asking you to buy it. I&amp;#8217;m recommending we buy at least one copy for work, and I recommend you check it out if you want to make effective applications.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=JTbn-Jdq-m4:PtNf4WHUp00:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=JTbn-Jdq-m4:PtNf4WHUp00:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=JTbn-Jdq-m4:PtNf4WHUp00:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=JTbn-Jdq-m4:PtNf4WHUp00:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=JTbn-Jdq-m4:PtNf4WHUp00:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=JTbn-Jdq-m4:PtNf4WHUp00:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=JTbn-Jdq-m4:PtNf4WHUp00:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/JTbn-Jdq-m4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/wireframe-your-interfaces-first</feedburner:origLink></entry>
 
 <entry>
   <title>Learning Mathematics</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/eICsY_SVAm4/learning-mathematics" />
   <updated>2008-12-14T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/learning-mathematics</id>
   <content type="html">&lt;p&gt;Although I&amp;#8217;m proud of my education and work experience thus far, the most important thing I have come to realise is where the vast gaps in my education &lt;em&gt;are.&lt;/em&gt; A little too late did I realise that the degree I really wanted was Computer Science, and instead I studied Software Engineering.&lt;/p&gt;
&lt;p&gt;If you need someone to analyse a complex problem and break it down into it&amp;#8217;s components, I can do that. If you need someone to manage a project and make sure your resources are optimised, I&amp;#8217;m your man. &lt;/p&gt;
&lt;p&gt;However, during my degree, we only breifly touched on mathematics and algorithms. If I recall correctly, we covered some basic boolean logic and very basically touched on sets. We didn&amp;#8217;t really get into the nitty gritty stuff that I&amp;#8217;ve seen CompSci graduates talk about.&lt;/p&gt;
&lt;p&gt;However, I&amp;#8217;m not the kind of person who would shrug &amp;#8220;Oh well&amp;#8221; and go about my business &amp;#8211; I&amp;#8217;m taking it upon myself to learn in my own time.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t know how other people learn. Although I&amp;#8217;ve done a little reading into it, I&amp;#8217;m still trying to come to terms with how I learn. While trying to study mathematics, I&amp;#8217;ve realised I have a tendency to explore various elements of a topic in depth &amp;#8211; I tend to dive into the intricacies of a concept, then go back to the shallow level and move on to a new concept.&lt;/p&gt;
&lt;p&gt;However, I&amp;#8217;ve found that this is very difficult to do with mathematics. All of the higher level concepts rely on lower level concepts, and there is much cross referencing. I might be looking into &lt;a title="Euler's Totient function - Wikipedia" href="http://http://en.wikipedia.org/wiki/Euler's_totient_function"&gt;Euler&amp;#8217;s Totient function&lt;/a&gt;, which will lead me to the concept of &lt;a title="Coprimes - Wikipedia" href="http://en.wikipedia.org/wiki/Coprime"&gt;coprimes&lt;/a&gt;, which will lead me to &lt;a title="Algebraic Rings - Wikipedia" href="http://en.wikipedia.org/wiki/Ring_(algebra)"&gt;rings&lt;/a&gt;, which are contrasted to &lt;a title="Groups - Wikipedia" href="http://en.wikipedia.org/wiki/Group_(mathematics)"&gt;groups&lt;/a&gt;, which were referenced back in the totient function! What&amp;#8217;s worse is all of these topics, especially the more abstractable rings and groups, extend past the real number systems, which I haven&amp;#8217;t even considered yet.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve found the best way to learn mathematics is to go broad and shallow, pick up the basic concept of all related concepts, then slowly work your way down. It results in a kind of net of understanding that isn&amp;#8217;t complete, but allows a person to easily recognise holes, and more intuitively link concepts together.&lt;/p&gt;
&lt;p&gt;Learning methods and methods of thinking are both subjects that fascinate me, and I&amp;#8217;ll probably have a deeper look into it when I get some time. I think these topics have a vast impact one what kind of knowledge people can learn easily, and can account for people having a &amp;#8220;knack&amp;#8221; for something.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eICsY_SVAm4:0huZv4gtZcg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eICsY_SVAm4:0huZv4gtZcg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=eICsY_SVAm4:0huZv4gtZcg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eICsY_SVAm4:0huZv4gtZcg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=eICsY_SVAm4:0huZv4gtZcg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=eICsY_SVAm4:0huZv4gtZcg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=eICsY_SVAm4:0huZv4gtZcg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/eICsY_SVAm4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/learning-mathematics</feedburner:origLink></entry>
 
 <entry>
   <title>Compile a User Control as a DLL</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/Zobivt-mt-g/compile-a-user-control-as-a-dll" />
   <updated>2008-12-07T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/compile-a-user-control-as-a-dll</id>
   <content type="html">&lt;p&gt;At work, I&amp;#8217;m redeveloping the old, &lt;span class="caps"&gt;ASP&lt;/span&gt; 3.0 &lt;span class="caps"&gt;CMS&lt;/span&gt; application and replacing it with a shiny new .&lt;span class="caps"&gt;NET&lt;/span&gt; 3.5 implementation. The software is designed to be run as a virtual directory from all websites, and thus shares the same from installation to installation.&lt;/p&gt;
&lt;p&gt;The old &lt;span class="caps"&gt;CMS&lt;/span&gt; is a mutant. It started as an &lt;span class="caps"&gt;ASP&lt;/span&gt; 3.0 application, and then had extra bits made of .&lt;span class="caps"&gt;NET&lt;/span&gt; 1.0 &amp;amp; .&lt;span class="caps"&gt;NET&lt;/span&gt; 2.0 tacked on to it, much in the same manner that Frankenstein&amp;#8217;s monster was created. The core &lt;span class="caps"&gt;ASP&lt;/span&gt; 3.0 application handled the page/news creation and publishing, and served as the interface.&lt;/p&gt;
&lt;p&gt;The additions were mostly in the form of user controls (.ascx files) that were placed in the content for a page that needed one. These user controls took care of things like random image rotators, contact forms, bread crumb menus, etc. Various sites used a various sub-section of a pool of controls.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;modus operandi&lt;/em&gt; with the current system is that each installation has it&amp;#8217;s own collection of controls which are inserted into pages by us on behalf of the client, because it involves putting &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; markup into the content areas.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve decided this isn&amp;#8217;t such a great idea, and as such, I&amp;#8217;m centralising the user controls as a library, seperate from the &lt;span class="caps"&gt;CMS&lt;/span&gt;, so that each site accesses the single pool of controls, and if a client leaves, it will be relatively simple to recompile a new library with the controls they use.&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;#8217;s the back story. Essentially what I need to do is compile a whole load of .ascx files into a dll, and load them into pages. I&amp;#8217;ve spent all morning looking on Google for &lt;a title="&amp;quot;.net 3.5 compile ascx dll&amp;quot; - Google Search" href="http://www.google.com.au/search?q=.net+3.5+compile+ascx+.dll"&gt;tips on how to do this&lt;/a&gt;. And frankly the results were less than helpful, however I have a history of &lt;a title="Twitter status post" href="http://twitter.com/tgittos/status/1039617602"&gt;not reading documentation&lt;/a&gt; &lt;a title="Reply Twitter status" href="http://twitter.com/tgittos/status/1039622067"&gt;properly&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What I found out you need to do, is to add a &lt;strong&gt;class library&lt;/strong&gt; project to your solution, and add the .ascx file as per normal. However, you need to do several steps to get this working properly:&lt;br /&gt;
&lt;ul&gt;&lt;br /&gt;
	&lt;li&gt;Go to the properties of your .ascx file and change the &lt;strong&gt;build action&lt;/strong&gt; to &lt;strong&gt;Embedded Resource.&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;From your control declaration on the .ascx file, delete &lt;strong&gt;AutoEventWireup&lt;/strong&gt;. We need to wire these things up ourselves. Personally I cleared it of everything except the language attribute.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;In the old code behind (now unattached class file) for the .ascx, you need to override the &lt;strong&gt;OnLoad&lt;/strong&gt; event handler, and put the following code:&lt;br /&gt;
[sourcecode language=&amp;#8220;csharp&amp;#8221;]&lt;br /&gt;
string content = String.Empty;&lt;br /&gt;
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), &amp;#8220;example.ascx&amp;#8221;);&lt;br /&gt;
using (StreamReader reader = new StreamReader(stream))&lt;br /&gt;
{&lt;br /&gt;
content = reader.ReadToEnd();&lt;br /&gt;
}&lt;br /&gt;
Control userControl = Page.ParseControl(content);&lt;br /&gt;
this.Controls.Add(control);&lt;br /&gt;
[/sourcecode]&lt;br /&gt;
This source will use reflection to open the currently executing dll (in this case, our .ascx library) and find the content for the .ascx, parse it as a new control and add it to the currently executing context.&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;For every control on the .ascx, in our now orphaned .ascx.cs you need to declare a private/protected variable of the same time, with the same variable name as the ID on the control (for sanity&amp;#8217;s sake). You need to find this control in our newly loaded .ascx and assign a reference:&lt;br /&gt;
[sourcecode language=&amp;#8220;csharp&amp;#8221;]&lt;br /&gt;
labelInAscx = (Label)control.FindControl(&amp;#8220;labelInAscx&amp;#8221;);&lt;br /&gt;
[/sourcecode]&lt;/li&gt;&lt;br /&gt;
	&lt;li&gt;The above two steps is exactly what the &lt;strong&gt;AutoWireUp&lt;/strong&gt; attribute on the control declaration does for you. We do it manually because we have to use reflection to extract the content of the ascx file, which is compiled into our dll.&lt;/li&gt;&lt;/p&gt;
&lt;/ul&gt;
&lt;p&gt;After taking these steps, compile your project, and in another project, on a regular aspx page, register the assembly and use as you would any normal .ascx and hopefully the content will render out fine.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.timgittos.com/wordpress/wp-content/uploads/2009/01/compileascxdll.zip"&gt;Compile .ascx as &lt;span class="caps"&gt;DLL&lt;/span&gt; solution for Visual Studio 2008&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Zobivt-mt-g:3tSgVty44aY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Zobivt-mt-g:3tSgVty44aY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Zobivt-mt-g:3tSgVty44aY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Zobivt-mt-g:3tSgVty44aY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Zobivt-mt-g:3tSgVty44aY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=Zobivt-mt-g:3tSgVty44aY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=Zobivt-mt-g:3tSgVty44aY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/Zobivt-mt-g" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/compile-a-user-control-as-a-dll</feedburner:origLink></entry>
 
 <entry>
   <title>0.999... = 1 Is Important</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/cCvP8wjORUc/09-1-is-important" />
   <updated>2008-12-04T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/09-1-is-important</id>
   <content type="html">&lt;p&gt;Before I get into this, I am not a mathematician. I&amp;#8217;m not even an amateur. I&amp;#8217;m just a guy who barely passed high school math 7 years ago, and who is interested in learning more.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s a generally accepted (though not completely) fact that 0.999&amp;#8230; = 1. I&amp;#8217;m not going to go into proofs, however if you need to see for yourself, you can find some at the &lt;a title="0.999... - Wikipedia" href="http://en.wikipedia.org/wiki/0.999..."&gt;Wikipedia article for 0.999&amp;#8230;&lt;/a&gt; And I&amp;#8217;m not going to debate or even acknowledge that people disagree, because that&amp;#8217;s not the point of this post.&lt;/p&gt;
&lt;p&gt;The point is, that 0.999&amp;#8230; = 1 is an important concept that demonstrates the abstraction of the numeral from the number. The people who see 0.999&amp;#8230; = 1 and can&amp;#8217;t believe it, I believe, haven&amp;#8217;t adequately realised there is a difference between a number and a numeral.&lt;/p&gt;
&lt;p&gt;A numeral is a symbol that represents a number &amp;#8211; that&amp;#8217;s all it is. It is, of itself, inherently useless. The numeral doesn&amp;#8217;t mean anything without the number. However, a number itself has meaning, no matter what numeral you use to represent it. This is what&amp;#8217;s going on with 0.999&amp;#8230; = 1.&lt;/p&gt;
&lt;p&gt;The reason this distinction is important is one of advancement in mathematics, specifically in algebra and all other relatively abstract fields. When you realise that 1, the numeral, represents the number 1, and 0.999&amp;#8230; the numeral, can &lt;em&gt;also&lt;/em&gt; represent the number 1, you realise that 4/4 is also a valid numeral for the number 1. Then, it&amp;#8217;s just a very small step to understanding that x can represent the number 1, and that in the equation 2x + y = 5, y also represents a number, and we need to find out that number.&lt;/p&gt;
&lt;p&gt;Although the example I gave is trivial, I believe it&amp;#8217;s an important concept to grasp, and it&amp;#8217;s a concept many people don&amp;#8217;t grasp.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=cCvP8wjORUc:cQg8CCwQiFc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=cCvP8wjORUc:cQg8CCwQiFc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=cCvP8wjORUc:cQg8CCwQiFc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=cCvP8wjORUc:cQg8CCwQiFc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=cCvP8wjORUc:cQg8CCwQiFc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=cCvP8wjORUc:cQg8CCwQiFc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=cCvP8wjORUc:cQg8CCwQiFc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/cCvP8wjORUc" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/09-1-is-important</feedburner:origLink></entry>
 
 <entry>
   <title>Adobe AIR 1.5 Update Framework</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/HCo4iOliOFo/adobe-air-15-update-framework" />
   <updated>2008-12-03T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/adobe-air-15-update-framework</id>
   <content type="html">&lt;p&gt;Lately I&amp;#8217;ve been working on a small &lt;a title="Adobe AIR" href="http://www.adobe.com/products/air/"&gt;Adobe &lt;span class="caps"&gt;AIR&lt;/span&gt;&lt;/a&gt; application, and one of the last things I had to do for this application was build in auto-update functionality. So, naturally, I hit the &lt;a title="Google is wise" href="http://www.google.com"&gt;all knowing sage&lt;/a&gt; with my question, and found many blog posts referencing the official Adobe &lt;span class="caps"&gt;AIR&lt;/span&gt; Update Framework, an additional swc library you can download and include in your project.&lt;/p&gt;
&lt;p&gt;Last night I found out that this framework has been rolled into the latest &lt;span class="caps"&gt;AIR&lt;/span&gt; 1.5 &lt;span class="caps"&gt;SDK&lt;/span&gt;, so I checked my version and downloaded the update. My experience with the Flex &lt;span class="caps"&gt;SDK&lt;/span&gt; told me I&amp;#8217;d have to find the &lt;span class="caps"&gt;SDK&lt;/span&gt; path in Flex Builder and point it to my new &lt;span class="caps"&gt;SDK&lt;/span&gt; to get the auto-update goodness.&lt;/p&gt;
&lt;p&gt;This, however, was not the case &amp;#8211; there was no variable. So I searched more online for the answers to my question, and finally found &lt;a title="Adobe AIR - Distributing and Updating Applications" href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7ff2.html"&gt;some official Adobe documentation&lt;/a&gt;. After a quick browse through, I deemed this useless. I still could not find how to get access to the &lt;code&gt;ApplicationUpdaterUI&lt;/code&gt; class. &lt;/p&gt;
&lt;p&gt;Eventually I re-read that documentation, and a section that I &lt;em&gt;thought&lt;/em&gt; was incorrectly copied from the old update framework download actually held the key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You still need to copy the swc library to your project&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Only, the &lt;strong&gt;swc is in the &lt;span class="caps"&gt;AIR&lt;/span&gt; &lt;span class="caps"&gt;SDK&lt;/span&gt; package&lt;/strong&gt;, not available as a separate download. Having copied the library to my project, I then had access to the auto-update goodness, but no thanks to Adobe&amp;#8217;s confusing documentation.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=HCo4iOliOFo:V81g0MvdbQs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=HCo4iOliOFo:V81g0MvdbQs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=HCo4iOliOFo:V81g0MvdbQs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=HCo4iOliOFo:V81g0MvdbQs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=HCo4iOliOFo:V81g0MvdbQs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=HCo4iOliOFo:V81g0MvdbQs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=HCo4iOliOFo:V81g0MvdbQs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/HCo4iOliOFo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/adobe-air-15-update-framework</feedburner:origLink></entry>
 
 <entry>
   <title>Interconnectivity of Media</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/-VhUDz4Q99Q/interconnectivity-of-media" />
   <updated>2008-11-27T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/interconnectivity-of-media</id>
   <content type="html">&lt;p&gt;On the 27th of November, 2008, terrorists attacked Mumbai, India. They hit several places and killed 80 people (at the time of this post), and wounding many more.&lt;/p&gt;
&lt;p&gt;I first heard about this through &lt;span class="caps"&gt;MSN&lt;/span&gt; via my girlfriend, who sent me a news link. Twitter lit up, several tweets about people&amp;#8217;s reactions to the news, and with one of those tweets, a link to live &lt;span class="caps"&gt;CNN&lt;/span&gt; footage streaming online direct from Mumbai. A quick look on Google trends showed that the news of the events in India have circled the globe in less than 24 hours.&lt;/p&gt;
&lt;p&gt;I saw this as well during the US Presidential elections, and it was even more intense. Twitter was non-stop tweeting about the various speeches and states, every major international news site had a streaming video and up to date Flash based maps for voting, and Google trends was all about the election and Prop 8. I was watching live footage of Obama&amp;#8217;s and McCain&amp;#8217;s speeches, and footage from Kenya.&lt;/p&gt;
&lt;p&gt;I felt it then, and I feel it now: overwhelming awe.&lt;/p&gt;
&lt;p&gt;The growth of the internet since 1983, away from a purely academic/military network with text only media, to today with streaming video and interactive content, has truly made our world a global community.&lt;/p&gt;
&lt;p&gt;Working day to day on the internet, creating websites to further the individual causes of various people, it&amp;#8217;s easy to lose site of how awesome the internet really is, and how interconnected everything is these days.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s nice to be able to take a step back.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=-VhUDz4Q99Q:7aN9d-qAfFE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=-VhUDz4Q99Q:7aN9d-qAfFE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=-VhUDz4Q99Q:7aN9d-qAfFE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=-VhUDz4Q99Q:7aN9d-qAfFE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=-VhUDz4Q99Q:7aN9d-qAfFE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=-VhUDz4Q99Q:7aN9d-qAfFE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=-VhUDz4Q99Q:7aN9d-qAfFE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/-VhUDz4Q99Q" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/interconnectivity-of-media</feedburner:origLink></entry>
 
 <entry>
   <title>Wordpress Or Roll Your Own</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/D_XN20FbfxE/wordpress-or-roll-your-own" />
   <updated>2008-11-26T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/wordpress-or-roll-your-own</id>
   <content type="html">&lt;p&gt;Laziness is a good quality for a programmer to have. Code reuse is smart, it&amp;#8217;s fast and efficient, and leads to less bugs (depending on how popular the code you use is).&lt;/p&gt;
&lt;p&gt;I know this.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve known this since university. Do I do it? I&amp;#8217;m starting to, I&amp;#8217;m slowly learning it. This is relevant, because prior to setting up Wordpress on my server, I developed roughly 4 version of my own &lt;span class="caps"&gt;PHP&lt;/span&gt; blogging platform. Two of them were relatively usable though still buggy, and 2 of them never made it past the full execution stack stage.&lt;/p&gt;
&lt;p&gt;Now, when I phrase it like this, it doesn&amp;#8217;t seem so bad, but I was constantly referencing Wordpress admin screen shots and had installs of Wordpress, Joomla and Drupal to pick and choose interface elements and functionality that I liked from these software applications.&lt;/p&gt;
&lt;p&gt;I had planned to start from scratch and slowly build up the featureset of my application to match those of the more popular open source applications. And to get experience I planned to use these applications&amp;#8230; but only in a sandbox, which was not publicly accessible.&lt;/p&gt;
&lt;p&gt;At the same time as trying to develop, in my own time, my own blogging/&lt;span class="caps"&gt;CMS&lt;/span&gt; solution, I&amp;#8217;m upgrading the &lt;span class="caps"&gt;CMS&lt;/span&gt; we use at work. This upgrade is a complete rewrite, migrating the funcitonality from &lt;span class="caps"&gt;ASP&lt;/span&gt; Classic to &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt;. This involves designing and developing, on my own, a fully functioning &lt;span class="caps"&gt;CMS&lt;/span&gt; system with support for page editing and a news section.&lt;/p&gt;
&lt;p&gt;So I was spending all time at work during the day creating an &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; &lt;span class="caps"&gt;CMS&lt;/span&gt;, then coming home at the end of the day to fire up Zend Studio and do &lt;em&gt;the exact same thing&lt;/em&gt; in &lt;span class="caps"&gt;PHP&lt;/span&gt;. I was reluctant to program, and the application was stalling, and I wasn&amp;#8217;t blogging.&lt;/p&gt;
&lt;p&gt;And the worst, I wasn&amp;#8217;t aware of &lt;em&gt;why&lt;/em&gt; I was stalling, and why I didn&amp;#8217;t want to work on it. I would spend my time at home goofing off, watching movies and chatting to friends. At least I had the intelligence to sit down and design a theme for my blog, once the code was finished. But I still wasn&amp;#8217;t developing the blog engine, and the whole process became this big elephant in the room that I was trying to ignore, blocking the doorway to me finally starting to do something I&amp;#8217;ve been wanting to do for a while.&lt;/p&gt;
&lt;p&gt;I didn&amp;#8217;t realise the lunacy of what I was doing until I stepped back and started programming something else entirely unrelated to both &lt;span class="caps"&gt;PHP&lt;/span&gt; and blogs. Once I had done so I realised a shocking truth: &lt;strong&gt;I don&amp;#8217;t even like programming websites.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At least, not in my own time.&lt;/p&gt;
&lt;p&gt;Programming blog engines and CMSes isn&amp;#8217;t something I want to spend all my time doing. I want to work on other projects, push the boundaries of my own knowledge &amp;#8211; but the blog/&lt;span class="caps"&gt;CMS&lt;/span&gt; thing is a rut that I&amp;#8217;ve fallen into. Been there, done that, I know the problem well and I know the solution well.&lt;/p&gt;
&lt;p&gt;So, something to take away from my experience is this:&lt;/p&gt;
&lt;p&gt;Unless your business/hobby/passion is writing blog engines, just use an off the shelf one. Your time is better spent &lt;em&gt;actually&lt;/em&gt; blogging than writing a blog engine. You learn more, it&amp;#8217;s generally more interesting, and you&amp;#8217;re creating content sooner.&lt;/p&gt;
&lt;p&gt;And isn&amp;#8217;t content what it&amp;#8217;s all about in the end?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=D_XN20FbfxE:3TOAqj40-8Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=D_XN20FbfxE:3TOAqj40-8Q:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=D_XN20FbfxE:3TOAqj40-8Q:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=D_XN20FbfxE:3TOAqj40-8Q:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=D_XN20FbfxE:3TOAqj40-8Q:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=D_XN20FbfxE:3TOAqj40-8Q:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=D_XN20FbfxE:3TOAqj40-8Q:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/D_XN20FbfxE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/wordpress-or-roll-your-own</feedburner:origLink></entry>
 
 <entry>
   <title>Why Blog?</title>
   <link href="http://feedproxy.google.com/~r/TimGittos/~3/h9_sa7zxUV0/why-blog" />
   <updated>2008-11-25T00:00:00-08:00</updated>
   <id>http://www.timgittos.com/archives/why-blog</id>
   <content type="html">&lt;p&gt;Or to put it another way, why you should care about this blog.&lt;/p&gt;
&lt;p&gt;Just in setting this blog up, I&amp;#8217;ve learnt many things, many things that I can share with people. Is this why I&amp;#8217;m choosing to blog? Partially. But the really compelling reason is learning.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve often heard it said that if you want to learn more about something, teach it. Through experiences on online forums, helping people with code, I find that this is a true statement. However, teaching in a classroom is beyond me &amp;#8211; both in terms of time and in terms of relative skill levels. So I&amp;#8217;m turning to the internet, a blog, to write about and share my experiences. Not because I think I&amp;#8217;m qualified to teach &lt;em&gt;anyone, &lt;/em&gt;but because I&amp;#8217;m not.&lt;/p&gt;
&lt;p&gt;So, we come back to the question, &amp;#8220;who is this guy, and why should I listen to him?&amp;#8221;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m a 24 year old developer currently living in Perth, Western Australia. I have a Bachelor of Science (Software Engineering) that I obtained from the Edith Cowan University. I have been working in the field of programming since late 2005. I have worked as a debugger/maintenance programmer for a desktop application for a now gone Perth startup, I have worked as a one-stop web development shop for a small company that also doesn&amp;#8217;t exist, and am currently a backend developer for a web development company.&lt;/p&gt;
&lt;p&gt;But none of that is important.&lt;/p&gt;
&lt;p&gt;I have worked in Actionscript 2.0, Director Lingo, &lt;span class="caps"&gt;ASP&lt;/span&gt; 3.0, &lt;span class="caps"&gt;PHP&lt;/span&gt;, &lt;span class="caps"&gt;ASP&lt;/span&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; (C#) and Actionscript 3.0, all in major projects. I have worked extensively with MySQL, PostgreSQL and &lt;span class="caps"&gt;SQL&lt;/span&gt; Server. I have developed both desktop applications and web applications, as well as web services and desktop Windows services. I am familiar with Windows OSes, OS X and Linux based systems. I can adequately administrate both &lt;span class="caps"&gt;IIS&lt;/span&gt; and Apache servers.&lt;/p&gt;
&lt;p&gt;None of that is important either.&lt;/p&gt;
&lt;p&gt;What &lt;strong&gt;is&lt;/strong&gt; important is that I have made mistakes. A lot of mistakes. About 10 years worth of mistakes. From those mistakes, I have learnt a lot, and I have clear goals in life.&lt;br /&gt;
I have made lifestyle mistakes, scholastic mistakes, career mistakes and mistakes in programming. I have tanked a couple of large projects, and have sabotaged my own efforts at starting and maintaining a small business.&lt;/p&gt;
&lt;p&gt;From these mistakes comes a passion for correcting what I can &amp;#8211; and to do that, I have to learn. I have to upgrade my skills, I have to grow as a person. I intend to do that by writing about them. Both to sort my own thoughts out, and to recieve feedback and learn from that feedback.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s why you should listen to me. And tell me when I&amp;#8217;m wrong, and tell me when I&amp;#8217;m being stupid and tell me when I am getting it right.&lt;/p&gt;
&lt;p&gt;I want to learn everything I can, and while learning, hopefully give something back.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=h9_sa7zxUV0:sSkgudHT4bU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=h9_sa7zxUV0:sSkgudHT4bU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=h9_sa7zxUV0:sSkgudHT4bU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=h9_sa7zxUV0:sSkgudHT4bU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=h9_sa7zxUV0:sSkgudHT4bU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TimGittos?a=h9_sa7zxUV0:sSkgudHT4bU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TimGittos?i=h9_sa7zxUV0:sSkgudHT4bU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TimGittos/~4/h9_sa7zxUV0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.timgittos.com/archives/why-blog</feedburner:origLink></entry>
 
 
</feed>
