<?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:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CUMMQXs9eSp7ImA9WhVTFE0.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130</id><updated>2012-02-27T23:31:20.561-05:00</updated><category term="Personal" /><category term="Celebrations" /><category term="Wordpress" /><category term="LibreOffice" /><category term="Performance" /><category term="Relationships" /><category term="Amazon" /><category term="Review" /><category term="Technorati" /><category term="Chromium OS" /><category term="Zend Framework" /><category term="How-To" /><category term="Programming" /><category term="Froyo" /><category term="Chromium" /><category term="Gentoo" /><category term="Picasa" /><category term="Communications" /><category term="TDD" /><category term="Hosting" /><category term="Backup" /><category term="Git" /><category term="Privacy" /><category term="SSL" /><category term="Series" /><category term="Storage" /><category term="Ruby on Rails" /><category term="Spam" /><category term="Android" /><category term="EC2" /><category term="Design Patterns" /><category term="Docs" /><category term="GMail" /><category term="Online Storage" /><category term="MySQL" /><category term="Internet" /><category term="Test Driven Development" /><category term="Drivers" /><category term="Subversion" /><category term="Cloud Computing" /><category term="Nexus One" /><category term="Input" /><category term="Portage" /><category term="RSync" /><category term="Localization" /><category term="Design" /><category term="Google" /><category term="Memorial Day" /><category term="PHP" /><category term="NFS" /><category term="iPhone" /><category term="HA" /><category term="Upgrade" /><category term="Linux" /><category term="VPS" /><category term="PHPUnit" /><category term="Angular" /><category term="mod_rewrite" /><category term="Notebook" /><category term="Update" /><category term="Patterns" /><category term="Ubuntu" /><category term="Rant" /><category term="Bash" /><category term="Databases" /><category term="Information" /><category term="Buzz" /><category term="Google Apps" /><category term="Installation" /><category term="OS" /><title>niden.net</title><subtitle type="html">"Boldly goes where no coder has gone before... and other ramblings"</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.niden.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.niden.net/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>45</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/niden" /><feedburner:info uri="niden" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DkAAQHY-fSp7ImA9WhRVF08.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-6956483791226250152</id><published>2012-01-15T15:44:00.000-05:00</published><updated>2012-01-16T09:39:01.855-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-16T09:39:01.855-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="Linux" /><category scheme="http://www.blogger.com/atom/ns#" term="PHPUnit" /><category scheme="http://www.blogger.com/atom/ns#" term="Installation" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><title>Downgrading PHPUnit from 3.6 to 3.5 [PHPUnit][Linux][HowTo]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-ed19ux0EFWw/TxQ1jgbyhkI/AAAAAAAArEc/tXwC_QNwzQw/s1600/logo.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="285" src="http://2.bp.blogspot.com/-ed19ux0EFWw/TxQ1jgbyhkI/AAAAAAAArEc/tXwC_QNwzQw/s320/logo.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
Recently I had to rebuild my computer, and decided to install &lt;a href="http://www.linuxmint.com/"&gt;Linux Mint&lt;/a&gt; 12 (Lisa), which is a very lean installation - for my taste that is.&lt;br /&gt;
&lt;br /&gt;
Going through the whole process of reinstalling all the packages that I need or had, &lt;a href="http://www.phpunit.de/"&gt;PHPUnit&lt;/a&gt; was one of them. Easy enough a couple commands did the trick&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;sudo apt-get install php-pear
sudo pear upgrade PEAR
sudo pear config-set auto_discover 1
sudo pear install pear.phpunit.de/PHPUnit
&lt;/pre&gt;
&lt;br /&gt;
I wanted to run my tests after that, only to find an error in the execution:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;PHP Fatal error: &amp;nbsp;Call to undefined method PHPUnit_Util_Filter::addFileToFilter()&lt;/pre&gt;
&lt;pre&gt; in /home/www/project/library/PHPUnit/Framework.php on line 48&lt;/pre&gt;
&lt;br /&gt;
At first I thought that it was a path error, so I included the /usr/share/php/PHPUnit and others in the php.ini file but with no luck. With a little bit of Googling I found out that there have been some changes in the 3.6 version of PHPUnit and things don't work as they did before.
&lt;br /&gt;
Effectively, 3.6 had some refactoring done and thus the line:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;PHPUnit_Util_Filter::addDirectoryToFilter("$dir/tests");
&lt;/pre&gt;
&lt;br /&gt;
changed to
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;PHP_CodeCoverage_Filter::getInstance()-&amp;gt;addDirectoryToBlacklist("$dir/tests");
&lt;/pre&gt;
&lt;br /&gt;
Since I didn't want to change my whole test suite, I had to find a solution i.e. downgrade PHPUnit to 3.5.&lt;br /&gt;
&lt;br /&gt;
Unfortunately specifying the version directly did not wok&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;sudo pear install phpunit/PHPUnit-3.5.15

&lt;/pre&gt;
since it would pull the latest version again and I would end up with the 3.6 files.&lt;br /&gt;
&lt;br /&gt;
So I went one step further and installed specific versions of the relevant dependencies to satisfy the 3.5.15 version.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Uninstallation of 3.6&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;pear uninstall phpunit/PHPUnit_Selenium
pear uninstall phpunit/PHPUnit
pear uninstall phpunit/DbUnit
pear uninstall phpunit/PHP_CodeCoverage
pear uninstall phpunit/PHP_Iterator
pear uninstall phpunit/PHPUnit_MockObject
pear uninstall phpunit/Text_Template
pear uninstall phpunit/PHP_Timer
pear uninstall phpunit/File_Iterator
pear uninstall pear.symfony-project.com/YAML

&lt;/pre&gt;
&lt;b&gt;Installation of 3.5.15&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;pear install pear.symfony-project.com/YAML-1.0.2
pear install phpunit/PHPUnit_Selenium-1.0.1
pear install phpunit/PHP_Timer-1.0.0
pear install phpunit/Text_Template-1.0.0
pear install phpunit/PHPUnit_MockObject-1.0.3
pear install phpunit/File_Iterator-1.2.3
pear install phpunit/PHP_CodeCoverage-1.0.2
pear install phpunit/DbUnit-1.0.0
pear install phpunit/PHPUnit-3.5.15

&lt;/pre&gt;
&lt;br /&gt;
I hope you find the above useful :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-6956483791226250152?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/8U79bve98bQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/6956483791226250152/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2012/01/downgrading-phpunit-from-36-to-35.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/6956483791226250152?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/6956483791226250152?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/8U79bve98bQ/downgrading-phpunit-from-36-to-35.html" title="Downgrading PHPUnit from 3.6 to 3.5 [PHPUnit][Linux][HowTo]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-ed19ux0EFWw/TxQ1jgbyhkI/AAAAAAAArEc/tXwC_QNwzQw/s72-c/logo.png" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2012/01/downgrading-phpunit-from-36-to-35.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUCR3o8eyp7ImA9WhRXFEw.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-3094162598562822784</id><published>2011-12-19T22:00:00.000-05:00</published><updated>2011-12-20T16:41:06.473-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-20T16:41:06.473-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="MySQL" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="Localization" /><category scheme="http://www.blogger.com/atom/ns#" term="Databases" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><category scheme="http://www.blogger.com/atom/ns#" term="Bash" /><title>Change the encoding of a MySQL database to UTF8 [How-To][PHP][MySQL]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-bTmAdRuC_iI/Tr79-FMfucI/AAAAAAAAFx0/WpAAcWzDzik/s1600/logomysql.gif" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="213" src="http://1.bp.blogspot.com/-bTmAdRuC_iI/Tr79-FMfucI/AAAAAAAAFx0/WpAAcWzDzik/s320/logomysql.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Overview&lt;/b&gt;&lt;br /&gt;
As applications grow, so do their audiences. In this day and age, one cannot assume that all the consumers of a web based application will live in a particular region and use only one language. Even if the developer assumes that one country will be served by the particular web application, there are instances that the latin1 character set will not suffice in storing data.&lt;br /&gt;
&lt;br /&gt;
Therefore, developers and database designers need to implement an encoding on their database that will safely store and retrieve any kind of data, not only latin1 based (i.e. the English alphabet).&lt;br /&gt;
&lt;br /&gt;
For MySQL this encoding is &lt;i&gt;utf8_general_ci&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The problem&lt;/b&gt;&lt;br /&gt;
MySQL usually comes with the &lt;i&gt;latin1_swedish_ci&lt;/i&gt; encoding as a default. This encoding will allow the developer to store data of course but when non latin1 characters need to be stored, there will be a problem. Effectively latin1 encoding will store data in 8 bits but some languages like Japanese, Thai, Arabic, even French or German have special characters that need more space in the storage engine. Trying to store a 16 bit character in a 8 bit space will fail all the time.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Latin1 based database:&lt;/i&gt;&lt;br /&gt;
Input: abcdef...ABCD...#$&lt;br /&gt;
Output: abcdef...ABCD...#$&lt;br /&gt;
&lt;br /&gt;
Input: 日本語 ภาษาไทย Ελληνικά&lt;br /&gt;
Output: ??? ??????? ????????&lt;br /&gt;
&lt;br /&gt;
To combat this, all you have to do is change the encoding of your database to &lt;i&gt;utf8_general_ci&lt;/i&gt; and the character set to &lt;i&gt;utf8&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The solution&lt;/b&gt;&lt;br /&gt;
I wrote a script in PHP to analyze a database server and produce ALTER statements to be executed against your database(s). The script needs to run from a web server that supports PHP.&lt;br /&gt;
&lt;br /&gt;
First of all, the encoding of the database will change with the relevant SQL statement. Following that each table's encoding will change, again with the relevant SQL statement. Finally, each TEXT/VARCHAR/CHAR etc. field's encoding will change towards the target encoding you specify in the configuration section (see below).&lt;br /&gt;
&lt;br /&gt;
The safest way to transform data this way is to first change the field to a BINARY field and then change the field to the target encoding and collation.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Configuration&lt;/i&gt;&lt;br /&gt;
There are a few configuration variables that need to be set prior to running the script.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;$db_user       = 'username';
$db_password   = 'password';
$db_host       = 'hostname';
$output_folder = '/home/ndimopoulos'; // Do not include trailing slash
$db_name       = 'mysql';             // Leave this one as is

set_time_limit(0);

/**
 * The old collation (what needs to be changed)
 */
$from_encoding = 'latin1_swedish_ci';

/**
 * The new collation (what we will change it to)
 */
$to_encoding = 'utf8_general_ci';

/**
 * The new character set
 */
$new_collation = 'utf8';

/**
 * Add USE &amp;lt;database&amp;gt;; before each statement?
 */
$use_database = TRUE;

&lt;/pre&gt;
The &lt;i&gt;$output_folder&lt;/i&gt; is a folder that is writeable from your web server and it is where the .sql files will be created filled with the ALTER statements. The script will output one file &lt;i&gt;&amp;lt;hostname&amp;gt;.sql&lt;/i&gt; which will contain all the ALTER statements for all databases. It will also create files for individual databases &lt;i&gt;&amp;lt;hostname&amp;gt;.&amp;lt;database&amp;gt;.sql&lt;/i&gt;. You can use either the big file or the individual database files. The choice is yours.&lt;br /&gt;
&lt;br /&gt;
The &lt;i&gt;$from_encoding&lt;/i&gt; is what the script will check. In my script I was checking '&lt;i&gt;latin1_swedish_ci&lt;/i&gt;'.&lt;br /&gt;
The &lt;i&gt;$to_encoding&lt;/i&gt; is what we need the encoding to be while the &lt;i&gt;$new_collation&lt;/i&gt; is the new character set.&lt;br /&gt;
&lt;br /&gt;
The &lt;i&gt;$use_database&lt;/i&gt; is a flag that will allow you to generate statements such as:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;USE &amp;lt;database&amp;gt;; ALTER TABLE &amp;lt;table&amp;gt;.....&lt;/pre&gt;
&lt;br /&gt;
if it is on, and if off, the statement will be:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;ALTER TABLE &amp;lt;table&amp;gt;.....&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Databases loop&lt;/i&gt;&lt;br /&gt;
The script opens a connection to the server and runs the '&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SHOW DATABASES&lt;/span&gt;' command. Based on the result returned, it populates an array with the database names.&lt;br /&gt;
&lt;br /&gt;
The script ignores two databases 'information_schema' and 'mysql', but editing the $exclude_databases array will allow you to ignore more databases if you need to.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;mysql_connect($db_host, $db_user, $db_password);
mysql_select_db($db_name);

$dbs = array();

exclude_databases = array('mysql', 'information_schema',);

/**
 * Get the databases available (ignore information_schema and mysql)
 */
$result = mysql_query("SHOW DATABASES");

while ($row = mysql_fetch_row($result))
{
    if (!in_array($row[0], $exclude_databases))
    {
        $dbs[] = $row[0];
    }&lt;/pre&gt;
&lt;pre&gt;}

&lt;/pre&gt;
The database names are stored in an array, so as not to keep the database resource active all the time. Had I not done that, I would have had to use three different resources (one for the database, one for the table and one for the field being checked - three nested loops).&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Tables loop&lt;/i&gt;&lt;br /&gt;
The script then loops through the $dbs array and selects each database in turn. Once the database is selected, the '&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SHOW TABLES&lt;/span&gt;' query is run and a $tables array is populated with the names of the tables in that database. At the same time the ALTER DATABASE statements are being generated.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;mysql_select_db($db);

$db_output = '';

$statement  = "\r\n#-------------------------------------------------\r\n\r\n";
$statement .= "USE $db;\r\n";
$statement .= "\r\n#-------------------------------------------------\r\n\r\n";
$statement .= "ALTER DATABASE $db "
            . "CHARACTER SET $new_collation COLLATE $to_encoding;\r\n";
$statement .= "\r\n#-------------------------------------------------\r\n\r\n";

$db_output .= $statement;
$output &amp;nbsp; &amp;nbsp;.= $statement;

$tables &amp;nbsp; &amp;nbsp; = array();

$result = mysql_query("SHOW TABLES");

while ($row = mysql_fetch_row($result))
{
    if (!in_array($row[0], $exclude_tables))
    {
        $tables[] = mysql_real_escape_string($row[0]);
    }
}
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Fields loop&lt;/i&gt;&lt;br /&gt;
The script then loops through the $tables array and runs the '&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SHOW FIELDS&lt;/span&gt;' query so as to analyze each field.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;$fields_modify = array();
$fields_change = array();

$result = mysql_query("SHOW FULL FIELDS FROM `$table`");
while ($row = mysql_fetch_assoc($result)) 
{
    if ($row['Collation'] != $from_encoding)
    {
        continue;
    }
   &amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    // Is the field allowed to be null?
    $nullable = ($row['Null'] == 'YES') ? ' NULL ' : ' NOT NULL';&lt;/pre&gt;
&lt;pre&gt;   &amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    if ($row['Default'] == 'NULL') 
    {
   &amp;nbsp;    $default = " DEFAULT NULL";&lt;/pre&gt;
&lt;pre&gt;    } 
    else if ($row['Default']!='') 
    {
   &amp;nbsp;    $default = " DEFAULT '" . mysql_real_escape_string($row['Default']) . "'";&lt;/pre&gt;
&lt;pre&gt;    } 
    else 
    {
   &amp;nbsp;    $default = '';&lt;/pre&gt;
&lt;pre&gt;    }
   &amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    // Alter field collation:
    $field_name = mysql_real_escape_string($row['Field']);
   &amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    $fields_modify[] = "MODIFY `$field_name` $row[Type] CHARACTER SET BINARY";
    $fields_change[] = "CHANGE `$field_name` `$field_name` $row[Type] "
                     . "CHARACTER SET $new_collation "&lt;/pre&gt;
&lt;pre&gt;                     . "COLLATE $to_encoding $nullable $default";&lt;/pre&gt;
&lt;pre&gt;}
&lt;/pre&gt;
&lt;br /&gt;
The two arrays generated (&lt;i&gt;$fields_modify&lt;/i&gt; and &lt;i&gt;$fields_change&lt;/i&gt; contain the MODIFY and CHANGE statements of each field. Using implode, we can easily construct the ALTER statement.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;$statement .= "ALTER TABLE `$table` " . implode(' , ', $fields_modify) . "; \r\n";
$statement .= "ALTER TABLE `$table` " . implode(' , ', $fields_change) . "; \r\n";
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Notes&lt;/b&gt;&lt;br /&gt;
You can use as mentioned earlier the &lt;i&gt;$exclude_databases&lt;/i&gt; array to not allow certain databases to be processed. You can also use the &lt;i&gt;$exclude_tables&lt;/i&gt; array to not allow certain tables to be processed.&lt;br /&gt;
&lt;br /&gt;
The &lt;i&gt;$exclude_tables_fields&lt;/i&gt; array allows you to exclude a field from being processed. However this is not tied to a database so any database/table that has a field with that particular name will not be processed. With a bit of refactoring you can make the script best work for your needs.&lt;br /&gt;
&lt;br /&gt;
If you set the &lt;i&gt;$use_database&lt;/i&gt; variable to TRUE then each line in your .sql statements will be prefixed with a '&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;USE &amp;lt;database&amp;gt;;&lt;/span&gt;' statement. This is to help the accompanying bash script to execute each statement in the respective database. If you intend on not running this process one statement at a time, you can set this to FALSE. You can then run each database .sql file (or the one that contains all of the statements from all databases) as one single command.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Server processing&lt;/b&gt;&lt;br /&gt;
Now that the relevant .sql files have been created, all you have to do is upload them on your web server. There are three ways of actually running the statements against the database.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;b&gt;Please make sure you backup your data first!&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;i&gt;Single file processing&amp;nbsp;&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;mysql -h&amp;lt;host&amp;gt; -u&amp;lt;username&amp;gt; -p&amp;lt;password&amp;gt; &amp;lt; /path/to/scripts/&amp;lt;host&amp;gt;.sql&lt;/pre&gt;
&lt;br /&gt;
The command above will run all the commands generated in the &amp;lt;host&amp;gt;.sql file for all databases. It is going to be taxing for your database server and there is no error handling or reporting. You can always pipe the results to an output file (just append "&lt;i&gt;&amp;gt; /path/to/output/output.txt&lt;/i&gt;" at the end of the command). If this method fails for some reason (MySQL has gone away), it will be difficult to resume; you will need to edit the &amp;lt;host&amp;gt;.sql file to remove the statements that have already been processed.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Per database&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;mysql -h&amp;lt;host&amp;gt; -u&amp;lt;username&amp;gt; -p&amp;lt;password&amp;gt; &amp;lt;database_name&amp;gt; &amp;lt; \&lt;/pre&gt;
&lt;pre&gt;       /path/to/scripts/&amp;lt;host&amp;gt;.&amp;lt;database&amp;gt;.sql&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The command above will run all the commands generated in the &amp;lt;host&amp;gt;.&amp;lt;database&amp;gt;.sql file for that particular database. This method is similar to the one above. Again you can always pipe the results to an output file (just append "&lt;i&gt;&amp;gt; /path/to/output/output.txt&lt;/i&gt;" at the end of the command).&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;i&gt;Single file processing (per statement)&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;/path/to/scripts/process.sh&lt;/pre&gt;
&lt;br /&gt;
All you need to do is edit the process.sh script and change the relevant parameters to match your environment and upload it to your server. The source file that the process.sh script will read has to be generated with &lt;i&gt;$use_database&lt;/i&gt;&amp;nbsp;set to TRUE.&lt;br /&gt;
&lt;br /&gt;
The process.sh script is:&lt;br /&gt;
&lt;pre&gt;#!/bin/bash

DBUSER=root
DBPASS=1234
DBHOST=localhost
SOURCE="/home/ndimopoulos/host.sql"
LOG="/home/ndimopoulos/conversion.log"

while read line
do
    TIMENOW=`date +%Y-%m-%d-%H-%M`
    echo START $TIMENOW $line
    echo START $TIMENOW $line &amp;gt;&amp;gt; $LOG
    /usr/bin/time -f "%E real,%U user,%S sys" -v -o $LOG -a mysql -h$DBHOST -u$DBUSER -p$DBPASS -e "$line"
    
    TIMENOW=`date +%Y-%m-%d-%H-%M`
    echo END $TIMENOW 
    echo END $TIMENOW &amp;gt;&amp;gt; $LOG

done &amp;lt; $SOURCE

exit 0
&lt;/pre&gt;
&lt;br /&gt;
The script above will start reading the source file (&amp;lt;host&amp;gt;.sql) and execute each statement in turn, using &lt;a href="http://en.wikipedia.org/wiki/Time_(Unix)"&gt;time&lt;/a&gt; to measure the time taken to execute that command. The output ends up in a log file which can easily be tailed to view the progress and used later on for analysis. The results of the processing are also sent to the screen. You can change the parameters for the time command to match your needs.&lt;br /&gt;
&lt;br /&gt;
The output will look something like the block below:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;START 2011-12-08-23-46 USE mydatabase; ALTER TABLE `tablename` DEFAULT CHARACTER SET utf8;
 Command being timed: "mysql -uroot -p1234 -e USE mydatabase; ALTER TABLE `tablename` DEFAULT CHARACTER SET utf8;"
 User time (seconds): 0.01
 System time (seconds): 0.00
 Percent of CPU this job got: 0%
 Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.16
 Average shared text size (kbytes): 0
 Average unshared data size (kbytes): 0
 Average stack size (kbytes): 0
 Average total size (kbytes): 0
 Maximum resident set size (kbytes): 8192
 Average resident set size (kbytes): 0
 Major (requiring I/O) page faults: 0
 Minor (reclaiming a frame) page faults: 610
 Voluntary context switches: 11
 Involuntary context switches: 5
 Swaps: 0
 File system inputs: 0
 File system outputs: 0
 Socket messages sent: 0
 Socket messages received: 0
 Signals delivered: 0
 Page size (bytes): 4096
 Exit status: 0
END 2011-12-08-23-46
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;
In order for a database to be best prepared to support localization, you need to make sure that the storage will accept any possible character. You can start by creating all your tables and fields with &lt;i&gt;utf8_general_ci&lt;/i&gt; encoding, but for existing databases and data, you will need to run expensive&amp;nbsp;processing&amp;nbsp;queries on your RDBMS. Ensuring that the data does not get corrupted when performing the transformation process is essential so make sure you backup your databases before trying or running the output statements produced by the db_alter.php script.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;PHP script (db_alter.php)&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;&lt;/pre&gt;
&lt;pre&gt;$db_user       = 'username';
$db_password   = 'password';
$db_host       = 'hostname';
$output_folder = '/home/ndimopoulos'; // Do not include trailing slash
$db_name       = 'mysql'; // Leave this one as is

set_time_limit(0);

/**
 * The old collation (what needs to be changed)
 */
$from_encoding = 'latin1_swedish_ci';

/**
 * The new collation (what we will change it to)
 */
$to_encoding = 'utf8_general_ci';

/**
 * The new character set
 */
$new_collation = 'utf8';

/**
 * Add USE &amp;lt;database&amp;gt; before each statement?
 */
$use_database = TRUE;

mysql_connect($db_host, $db_user, $db_password);
mysql_select_db($db_name);

$dbs = array();

$exclude_databases     = array('mysql', 'information_schema',);
$exclude_tables        = array('logs', 'logs_archived',);
$exclude_tables_fields = array('activities');

/**
 * Get the databases available (ignore information_schema and mysql)
 */
$result = mysql_query("SHOW DATABASES");

while ($row = mysql_fetch_row($result)) 
{
    if (!in_array($row[0], $exclude_databases))
    {
        $dbs[] = $row[0];
    }
}

$output = '';&lt;/pre&gt;
&lt;pre&gt;/**
 * Now select each db and start parsing the tables
 */
foreach ($dbs as $db)
{
    mysql_select_db($db);
    $db_output = '';
    
    $statement  = "\r\n#-----------------------------------------------\r\n\r\n";
    $statement .= "USE $db;\r\n";
    $statement .= "\r\n#-----------------------------------------------\r\n\r\n";
    $statement .= "ALTER DATABASE $db "
                . "CHARACTER SET $new_collation COLLATE $to_encoding;\r\n";
    $statement .= "\r\n#-----------------------------------------------\r\n\r\n";
    
    $db_output .= $statement;
    $output    .= $statement;
    $tables     = array();
    
    $result = mysql_query("SHOW TABLES");
    
    while ($row = mysql_fetch_row($result))
    {
        if (!in_array($row[0], $exclude_tables))
        {
            $tables[] = mysql_real_escape_string($row[0]);
        }
    }
    
    /**
     * Alter statements for the tables
     */
    foreach ($tables as $table)
    {
        $statement = '';
        if ($use_database)
        {
            $statement  = "USE $db; ";
        }
        $statement .= "ALTER TABLE `$table` "
                    . "DEFAULT CHARACTER SET $new_collation;\r\n";
        $db_output .= $statement;
        $output    .= $db_output;
    }
    $statement .= "\r\n#-----------------------------------------------\r\n\r\n";

    $db_output .= $statement;
    $output    .= $statement;
    
    /**
     * Get the fields for each table
     */
    foreach ($tables as $table)
    {
        if (in_array($table, $exclude_tables_fields))
        {
            continue;
        } 
        
        $fields_modify = array();
        $fields_change = array();
        
        $result = mysql_query("SHOW FULL FIELDS FROM `$table`");
        while ($row = mysql_fetch_assoc($result)) 
        {
            if ($row['Collation'] != $from_encoding)
            {
                continue;
            }
            
            // Is the field allowed to be null?
            $nullable = ($row['Null'] == 'YES') ? ' NULL ' : ' NOT NULL';
            
            if ($row['Default'] == 'NULL') 
            {
                $default = " DEFAULT NULL";
            } 
            else if ($row['Default']!='') 
            {
                $default = " DEFAULT '"
                         . mysql_real_escape_string($row['Default']) . "'";
            }
            else 
            {
                $default = '';
            }
            
            // Alter field collation:
            $field_name = mysql_real_escape_string($row['Field']);
            
            $fields_modify[] = "MODIFY `$field_name` $row['Type'] "
                             . "CHARACTER SET BINARY";
            $fields_change[] = "CHANGE `$field_name` `$field_name` $row['Type'] "
                             . "CHARACTER SET $new_collation "
                             . "COLLATE $to_encoding $nullable $default";
        }
        
        if (count($fields_modify) &amp;gt; 0)
        {
            $statement = '';
            if ($use_database)
            {
                $statement = "USE $db; ";
            }
            $statement .= "ALTER TABLE `$table` "
                        . implode(' , ', $fields_modify) . "; \r\n";
            if ($use_database)
            {
                $statement = "USE $db; ";
            }
            $statement .= "ALTER TABLE `$table` "
                        . implode(' , ', $fields_change) . "; \r\n";
            
            $db_output .= $statement;
            $output    .= $statement;
        }
    }
    
    $bytes = file_put_contents(
        $output_folder . '/' . $db_host . '.' . $db . '.sql', $db_output
    );
}
    
$bytes = file_put_contents($output_folder . '/' . $db_host . '.sql', $output);

echo "&amp;lt;pre&amp;gt;$db_host $bytes \r\n$output&amp;lt;/pre&amp;gt;";
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Downloads&lt;/b&gt;&lt;br /&gt;
You can use these scripts at your own risk. Also feel free to distribute them freely - a mention would be nice. Both scripts can be found in my &lt;a href="https://github.com/niden"&gt;GitHub&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-3094162598562822784?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/OzwjaCi93Fk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/3094162598562822784/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/12/change-encoding-of-mysql-database-to.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/3094162598562822784?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/3094162598562822784?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/OzwjaCi93Fk/change-encoding-of-mysql-database-to.html" title="Change the encoding of a MySQL database to UTF8 [How-To][PHP][MySQL]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-bTmAdRuC_iI/Tr79-FMfucI/AAAAAAAAFx0/WpAAcWzDzik/s72-c/logomysql.gif" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/12/change-encoding-of-mysql-database-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYFRXsycSp7ImA9WhRREEs.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-5929435911408963024</id><published>2011-11-22T17:34:00.001-05:00</published><updated>2011-11-23T12:08:34.599-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-23T12:08:34.599-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><category scheme="http://www.blogger.com/atom/ns#" term="Performance" /><title>Fast serialization of data in PHP [How-To][Performance]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-fKGt9OWGp7U/TswyoFFCBRI/AAAAAAAAMcY/9-cXDD5NCw0/s1600/sleep-wakeup-in-php.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-fKGt9OWGp7U/TswyoFFCBRI/AAAAAAAAMcY/9-cXDD5NCw0/s1600/sleep-wakeup-in-php.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Serializing/Unserializing data&lt;/b&gt;&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;Serialization is the process of converting a data structure or object state into a format that can be stored and "resurrected" later in the same or another computer environment. &lt;a href="http://en.wikipedia.org/wiki/Serialization"&gt;source&lt;/a&gt;&lt;/i&gt;&lt;/blockquote&gt;
There are a lot of areas where one can use serialization. A couple are:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;in a database (storing an array of options specific to the user),&amp;nbsp;&lt;/li&gt;
&lt;li&gt;in an AJAX enabled application (call to get a status update and display to the user without refreshing the whole page), etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Based on the the application, serializing and unserializing data can be a very intensive process and can prove to have a big performance hit on the overall system.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Options&lt;/b&gt;&lt;br /&gt;
The most obvious option for serializing and unserializing data are the &lt;a href="http://php.net/manual/en/function.serialize.php"&gt;serialize&lt;/a&gt; and &lt;a href="http://www.php.net/manual/en/function.unserialize.php"&gt;unserialize&lt;/a&gt; PHP functions. A bit less popular are &lt;a href="http://us3.php.net/manual/en/function.json-encode.php"&gt;json_encode&lt;/a&gt; and &lt;a href="http://us3.php.net/manual/en/function.json-decode.php"&gt;json_decode&lt;/a&gt;. There is also a third option, using a third party module that one can easily install on their server. This module is called &lt;a href="http://opensource.dynamoid.com/"&gt;igbinary&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
In this blog post I am comparing the three options, in the hope that it will aid you with your selection of the best option for you so as to increase the performance of your application.&lt;br /&gt;
&lt;br /&gt;
I created a test script that used several arrays of data (strings, integers, floats, booleans, objects, mixed data, all of the data types) to test the speed and size of the serialization and speed of unserialization of each of the three candidate function pairs. I run the same function to serialize or unserialize the data respectively for 1,000,000 times so as to produce the results below.&lt;br /&gt;
&lt;br /&gt;
The script that I have used is listed below:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;$_testStrings = array(
   'AK' =&amp;gt; 'Alaska', 'AZ' =&amp;gt; 'Arizona', 'VT' =&amp;gt; 'Vermont',
   'VA' =&amp;gt; 'Virginia', 'AZ' =&amp;gt; 'West Virginia',
);
 
$_testIntegers = array(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 84, 144,);

$_testBooleans = array(TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE,);
 
$_testFloats = array(
  0, 1.1, 1.1, 2.22, 3.33, 5.55, 8.88, 13.13, 21.2121, 34.3434, 
  55.5555, 84.8484, 144.144,
);
 
$_testMixed = array(
  'one', 13 =&amp;gt; 'two', 0 =&amp;gt; 25.46, 'four' =&amp;gt; 0.007, 'five' =&amp;gt; TRUE, TRUE =&amp;gt; 42,
);
 
$_objectOne             = new stdClass();
$_objectOne-&amp;gt;firstname  = 'Leroy';
$_objectOne-&amp;gt;lastname   = 'Jenkins';
$_objectOne-&amp;gt;profession = 'Gamer';
$_objectOne-&amp;gt;status     = 'Legend';
 
$_objectTwo         = new stdClass();
$_objectTwo-&amp;gt;series = 'Fibonacci';
$_objectTwo-&amp;gt;data   = $_testIntegers;
 
$_testObjects = array($_objectOne, $_objectTwo,);

$_maxLoop = 1000000;

$_templateEncode = "%s [%s]: Size: %s bytes, %s time to encode\r\n";
$_templateDecode = "%s [%s]: %s time to decode\r\n";

set_time_limit(0);

$_output = '';

/**
 * Set the source arrays
 */
$_allTestData = array(
   'str' =&amp;gt; $_testStrings,
   'int' =&amp;gt; $_testIntegers,
   'bln' =&amp;gt; $_testBooleans,
   'flt' =&amp;gt; $_testFloats,
   'mix' =&amp;gt; $_testMixed,
   'obj' =&amp;gt; $_testObjects,
);

$_testSources = array(
   'strings'  =&amp;gt; $_testStrings,
   'integers' =&amp;gt; $_testIntegers,
   'booleans' =&amp;gt; $_testBooleans,
   'floats'   =&amp;gt; $_testFloats,
   'mixed'    =&amp;gt; $_testMixed,
   'objects'  =&amp;gt; $_testObjects,
   'all'      =&amp;gt; $_allTestData,
);
 
/**
 * ENCODE DATA
 */

/**
 * Start each test
 */
foreach ($_testSources as $_area =&amp;gt; $_source)
{
 /**
  * Start the timer
  */
 $_serializeStart = microtime(TRUE);
 
 for ($_counter = 0; $_counter &amp;lt; $_maxLoop; $_counter++)
 {
  serialize($_source);
 }
 
 $_serializeEnd = microtime(TRUE);
 
 $_serializeOutput = serialize($_source);
 
 $_output .= sprintf(
  $_templateEncode,
  'serialize()', 
  $_area, 
  strlen($_serializeOutput), 
  $_serializeEnd - $_serializeStart
 );
 
 /**
  * JSON
  */
 $_jsonStart = microtime(TRUE);
 
 for ($_counter = 0; $_counter &amp;lt; $_maxLoop; $_counter++)
 {
  json_encode($_source);
 }
 
 $_jsonEnd = microtime(TRUE);
 
 $_jsonOutput = json_encode($_source);
 
 $_output .= sprintf(
  $_templateEncode,
  'json_encode()', 
  $_area, 
  strlen($_jsonOutput), 
  $_jsonEnd - $_jsonStart
 );
 
 /**
  * igbinary
  */
 $_igbinaryStart = microtime(TRUE);
 
 for ($_counter = 0; $_counter &amp;lt; $_maxLoop; $_counter++)
 {
  igbinary_serialize($_source);
 }
 
 $_igbinaryEnd = microtime(TRUE);
 
 $_igbinaryOutput = igbinary_serialize($_source);
 
 $_output .= sprintf(
  $_templateEncode,
  'igbinary_serialize()', 
  $_area, 
  strlen($_igbinaryOutput), 
  $_igbinaryEnd - $_igbinaryStart
 );
 
 $_output .= str_repeat('=', 20) . "\r\n";
}

$_output .= str_repeat('=:=', 20) . "\r\n";


/**
 * DECODE DATA
 */

/**
 * Start each test
 */
foreach ($_testSources as $_area =&amp;gt; $_source)
{
 /**
  * Start the timer
  */
 $_data = serialize($_source);
 
 $_serializeStart = microtime(TRUE);
 
 for ($_counter = 0; $_counter &amp;lt; $_maxLoop; $_counter++)
 {
  unserialize($_data);
 }
 
 $_serializeEnd = microtime(TRUE);
 
 $_output .= sprintf(
  $_templateDecode,
  'unserialize()', 
  $_area, 
  $_serializeEnd - $_serializeStart
 );
 
 /**
  * JSON
  */
 $_data = json_encode($_source);
 
 $_jsonStart = microtime(TRUE);
 
 for ($_counter = 0; $_counter &amp;lt; $_maxLoop; $_counter++)
 {
  json_decode($_data, TRUE);
 }
 
 $_jsonEnd = microtime(TRUE);
 
 $_jsonOutput = json_encode($_source);
 
 $_output .= sprintf(
  $_templateDecode,
  'json_decode()', 
  $_area, 
  $_jsonEnd - $_jsonStart
 );
 
 /**
  * igbinary
  */
 $_data = igbinary_serialize($_source);
 
 $_igbinaryStart = microtime(TRUE);
 
 for ($_counter = 0; $_counter &amp;lt; $_maxLoop; $_counter++)
 {
  igbinary_unserialize($_data);
 }
 
 $_igbinaryEnd = microtime(TRUE);
 
 $_igbinaryOutput = igbinary_serialize($_source);
 
 $_output .= sprintf(
  $_templateDecode,
  'igbinary_unserialize()', 
  $_area, 
  $_igbinaryEnd - $_igbinaryStart
 );
 
 $_output .= str_repeat('=', 20) . "\r\n";
}
 
echo '&amp;lt;pre&amp;gt;' . $_output . '&amp;lt;/pre&amp;gt;';
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Serializing results&lt;/b&gt;&lt;br /&gt;
When serializing data we are always concerned about the size of the result but also about the time it took for the data to be serialized.&lt;br /&gt;
&lt;br /&gt;
As far as size is concerned, I have highlighted in bold the winner of each test. json_encode seems to be producing the smallest result in bytes for most of the tests.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Size comparison&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://chart.apis.google.com/chart?chxr=0,0,1600&amp;amp;chxt=y&amp;amp;chbh=a&amp;amp;chs=400x205&amp;amp;cht=bvg&amp;amp;chco=A2C180,3D7930,FF9900&amp;amp;chds=5,1605,5,1605,0,1600&amp;amp;chd=t:105,121,62,709,178,326,1567|67,34,39,77,54,148,478|64,58,27,142,50,177,478&amp;amp;chdl=serialize|json_encode|igbinary&amp;amp;chtt=Size+Comparison" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="164" src="http://chart.apis.google.com/chart?chxr=0,0,1600&amp;amp;chxt=y&amp;amp;chbh=a&amp;amp;chs=400x205&amp;amp;cht=bvg&amp;amp;chco=A2C180,3D7930,FF9900&amp;amp;chds=5,1605,5,1605,0,1600&amp;amp;chd=t:105,121,62,709,178,326,1567|67,34,39,77,54,148,478|64,58,27,142,50,177,478&amp;amp;chdl=serialize|json_encode|igbinary&amp;amp;chtt=Size+Comparison" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;i&gt;Strings
&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [strings]: Size: 105 bytes, 1.8710339069366 time to encode
json_encode() [strings]: Size: 67 bytes, 1.5691390037537 time to encode
&lt;b&gt;igbinary_serialize() [strings]: Size: 64 bytes, 3.2276048660278 time to encode&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Integers&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [integers]: Size: 121 bytes, 3.0198090076447 time to encode
&lt;b&gt;json_encode() [integers]: Size: 34 bytes, 1.2248229980469 time to encode&lt;/b&gt;
igbinary_serialize() [integers]: Size: 58 bytes, 2.2877519130707 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Booleans&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [booleans]: Size: 62 bytes, 2.0834550857544 time to encode
json_encode() [booleans]: Size: 39 bytes, 1.0889070034027 time to encode
&lt;b&gt;igbinary_serialize() [booleans]: Size: 27 bytes, 1.8252439498901 time to encode&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Floats&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [floats]: Size: 709 bytes, 27.496570825577 time to encode
&lt;b&gt;json_encode() [floats]: Size: 77 bytes, 5.0476500988007 time to encode&lt;/b&gt;
igbinary_serialize() [floats]: Size: 142 bytes, 2.4856028556824 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Mixed
&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [mixed]: Size: 178 bytes, 6.301619052887 time to encode
json_encode() [mixed]: Size: 54 bytes, 2.0463008880615 time to encode
&lt;b&gt;igbinary_serialize() [mixed]: Size: 50 bytes, 2.3894169330597 time to encode&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Objects&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [objects]: Size: 326 bytes, 4.8698291778564 time to encode
&lt;b&gt;json_encode() [objects]: Size: 148 bytes, 2.4744520187378 time to encode&lt;/b&gt;
igbinary_serialize() [objects]: Size: 177 bytes, 6.472992181778 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;All data types&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [all]: Size: 1567 bytes, 42.437592029572 time to encode
&lt;b&gt;json_encode() [all]: Size: 462 bytes, 9.9569129943848 time to encode&lt;/b&gt;
igbinary_serialize() [all]: Size: 478 bytes, 18.053789138794 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Speed comparison&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://chart.apis.google.com/chart?chxr=0,0,50&amp;amp;chxt=y&amp;amp;chbh=a&amp;amp;chs=400x205&amp;amp;cht=bvg&amp;amp;chco=A2C180,3D7930,FF9900&amp;amp;chds=1.87,50,0,50,0,50&amp;amp;chd=t:1.87,3.02,2.08,27.5,6.3,4.87,42.44|1.57,1.22,1.09,5.05,2.05,2.47,9.96|3.23,2.29,1.82,2.48,2.39,6.47,18.05&amp;amp;chdl=serialize|json_encode|igbinary&amp;amp;chtt=Speed+Comparison&amp;amp;chts=676767,10.5" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="164" src="http://chart.apis.google.com/chart?chxr=0,0,50&amp;amp;chxt=y&amp;amp;chbh=a&amp;amp;chs=400x205&amp;amp;cht=bvg&amp;amp;chco=A2C180,3D7930,FF9900&amp;amp;chds=1.87,50,0,50,0,50&amp;amp;chd=t:1.87,3.02,2.08,27.5,6.3,4.87,42.44|1.57,1.22,1.09,5.05,2.05,2.47,9.96|3.23,2.29,1.82,2.48,2.39,6.47,18.05&amp;amp;chdl=serialize|json_encode|igbinary&amp;amp;chtt=Speed+Comparison&amp;amp;chts=676767,10.5" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
Analyzing the time it took for each test to be completed, we see again that json_encode is the clear winner (highlighted in bold the shortest time for the function).&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Strings&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [strings]: Size: 105 bytes, 1.8710339069366 time to encode
&lt;b&gt;json_encode() [strings]: Size: 67 bytes, 1.5691390037537 time to encode&lt;/b&gt;
igbinary_serialize() [strings]: Size: 64 bytes, 3.2276048660278 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Integers&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [integers]: Size: 121 bytes, 3.0198090076447 time to encode
&lt;b&gt;json_encode() [integers]: Size: 34 bytes, 1.2248229980469 time to encode&lt;/b&gt;
igbinary_serialize() [integers]: Size: 58 bytes, 2.2877519130707 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Booleans&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [booleans]: Size: 62 bytes, 2.0834550857544 time to encode
&lt;b&gt;json_encode() [booleans]: Size: 39 bytes, 1.0889070034027 time to encode&lt;/b&gt;
igbinary_serialize() [booleans]: Size: 27 bytes, 1.8252439498901 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Floats&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [floats]: Size: 709 bytes, 27.496570825577 time to encode
json_encode() [floats]: Size: 77 bytes, 5.0476500988007 time to encode
&lt;b&gt;igbinary_serialize() [floats]: Size: 142 bytes, 2.4856028556824 time to encode&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Mixed&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [mixed]: Size: 178 bytes, 6.301619052887 time to encode
&lt;b&gt;json_encode() [mixed]: Size: 54 bytes, 2.0463008880615 time to encode&lt;/b&gt;
igbinary_serialize() [mixed]: Size: 50 bytes, 2.3894169330597 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Objects&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [objects]: Size: 326 bytes, 4.8698291778564 time to encode
&lt;b&gt;json_encode() [objects]: Size: 148 bytes, 2.4744520187378 time to encode&lt;/b&gt;
igbinary_serialize() [objects]: Size: 177 bytes, 6.472992181778 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;All data types&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;serialize() [all]: Size: 1567 bytes, 42.437592029572 time to encode
&lt;b&gt;json_encode() [all]: Size: 462 bytes, 9.9569129943848 time to encode&lt;/b&gt;
igbinary_serialize() [all]: Size: 478 bytes, 18.053789138794 time to encode
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Combination&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
Having the smallest result in size might not always be the best metric to base the choice of the serialization algorithm. For instance, looking at the results above in the Strings test, igbinary produces indeed the smallest result in size (64 bytes) but it takes twice as much to serialize the result in comparison to json_encode (3.22 vs. 1.56 seconds) and the size difference is a mere 3 bytes (64 vs. 67).&lt;br /&gt;
&lt;br /&gt;
Similarly, for the Boolean test, igbinary produces 27 bytes and json_encode 39 bytes. It does however take igbinary nearly 80% more time to produce the result compared to json_encode.&lt;br /&gt;
&lt;br /&gt;
For the Floats test the situation is reversed. json_encode produces a result that is around 50% smaller than the one of igbinary but it takes twice as much time to produce it.&lt;br /&gt;
&lt;br /&gt;
As far as serializing data, in my personal opinion, json_encode is the clear winner.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Unserializing Results&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Unserializing data is equally - and at times - more important than serializing. In many applications, developers sacrifice performance in writing but don't compromise when reading data.&lt;br /&gt;
&lt;br /&gt;
In the tests below (shortest time highlighted in bold) once can easily see that igbinary is the clear winner. At times the unserialize function is very close (or outperforms igbinary) but overall, igbinary is the the function that unserializes data the fastest.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Speed comparison&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://chart.apis.google.com/chart?chxr=0,0,50&amp;amp;chxt=y&amp;amp;chbh=a&amp;amp;chs=400x205&amp;amp;cht=bvg&amp;amp;chco=A2C180,3D7930,FF9900&amp;amp;chds=0,35,0,35,0,35&amp;amp;chd=t:1.82,2.39,1.81,18.51,4.68,5.54,31.01|2.65,2.86,2.44,3.79,2.78,5.77,14.57|1.83,2.44,1.76,2.67,1.96,5.27,10.73&amp;amp;chdl=serialize|json_encode|igbinary&amp;amp;chtt=Speed+Comparison&amp;amp;chts=676767,10.5" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="164" src="http://chart.apis.google.com/chart?chxr=0,0,50&amp;amp;chxt=y&amp;amp;chbh=a&amp;amp;chs=400x205&amp;amp;cht=bvg&amp;amp;chco=A2C180,3D7930,FF9900&amp;amp;chds=0,35,0,35,0,35&amp;amp;chd=t:1.82,2.39,1.81,18.51,4.68,5.54,31.01|2.65,2.86,2.44,3.79,2.78,5.77,14.57|1.83,2.44,1.76,2.67,1.96,5.27,10.73&amp;amp;chdl=serialize|json_encode|igbinary&amp;amp;chtt=Speed+Comparison&amp;amp;chts=676767,10.5" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;i&gt;Strings&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;&lt;b&gt;unserialize() [strings]: 1.8259189128876 time to decode&lt;/b&gt;
json_decode() [strings]: 2.6482670307159 time to decode
igbinary_unserialize() [strings]: 1.8359968662262 time to decode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Integers
&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;&lt;b&gt;unserialize() [integers]: 2.3886890411377 time to decode&lt;/b&gt;
json_decode() [integers]: 2.8659090995789 time to decode
igbinary_unserialize() [integers]: 2.4441809654236 time to decode
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Booleans
&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;unserialize() [booleans]: 1.8097970485687 time to decode
json_decode() [booleans]: 2.4416139125824 time to decode
&lt;b&gt;igbinary_unserialize() [booleans]: 1.7585029602051 time to decode&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Floats
&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;unserialize() [floats]: 18.512004137039 time to decode
json_decode() [floats]: 3.7896130084991 time to decode
&lt;b&gt;igbinary_unserialize() [floats]: 2.6730649471283 time to decode&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Mixed
&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;unserialize() [mixed]: 4.6794769763947 time to decode
json_decode() [mixed]: 2.7775249481201 time to decode
&lt;b&gt;igbinary_unserialize() [mixed]: 1.9598047733307 time to decode&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Objects
&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;unserialize() [objects]: 5.5468521118164 time to decode
json_decode() [objects]: 5.7660481929779 time to decode
&lt;b&gt;igbinary_unserialize() [objects]: 5.2672090530396 time to decode&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;All data types&lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;unserialize() [all]: 31.01339006424 time to decode
json_decode() [all]: 14.574991941452 time to decode
&lt;b&gt;igbinary_unserialize() [all]: 10.734386920929 time to decode&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;
If your application is mostly focused on reads rather than writes, igbinary is the clear winner, since it will unserialize your data faster than the other two functions. If however you are more focused on storing data, json_encode is the clear choice.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-5929435911408963024?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/wtPd4Mf9yaM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/5929435911408963024/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/11/fast-serialization-of-data-in-php-how.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/5929435911408963024?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/5929435911408963024?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/wtPd4Mf9yaM/fast-serialization-of-data-in-php-how.html" title="Fast serialization of data in PHP [How-To][Performance]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-fKGt9OWGp7U/TswyoFFCBRI/AAAAAAAAMcY/9-cXDD5NCw0/s72-c/sleep-wakeup-in-php.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/11/fast-serialization-of-data-in-php-how.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcHSH4-eSp7ImA9WhRSEkU.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-21020081014996638</id><published>2011-11-13T13:45:00.001-05:00</published><updated>2011-11-14T10:03:59.051-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-14T10:03:59.051-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="Git" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><title>Git pre-commit - Another check to ensure clean code [How-To]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-9aU96_99ZbE/TsAeRgLvRdI/AAAAAAAAGkU/FwdPWCvLFUQ/s1600/git-logo.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-9aU96_99ZbE/TsAeRgLvRdI/AAAAAAAAGkU/FwdPWCvLFUQ/s1600/git-logo.png" /&gt;&lt;/a&gt;&lt;/div&gt;
Throughout my career I have been using various &lt;a href="http://en.wikipedia.org/wiki/Revision_control"&gt;revision control systems&lt;/a&gt;. I started off with Visual SourceSafe which I thought at the time was great, primarily because of the small size of our team and the ease of use though the Visual Basic's IDE.&lt;br /&gt;
&lt;br /&gt;
Later on I switched to SVN which is a great version control system and it fulfilled all my needs for proper version control.&lt;br /&gt;
&lt;br /&gt;
When I moved to the US and started working here, I introduced SVN to the company that I was working at the time. We adopted the technique of having one branch per project, since we were working on different projects at any given time. Using the plugin through Eclipse or in Windows the integrated Explorer plugin, I was checking in code, switching through projects etc.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.niden.net/2011/11/new-beginnings-sleep6566400.html"&gt;Recently&lt;/a&gt;&amp;nbsp;I changed jobs and although we did use Subversion for a few months, we did switch to Git. The reasons behind it are too many to count - and I will go through them in another blog post.&lt;br /&gt;
&lt;br /&gt;
One really good feature that Git has is its hooks. Although Subversion also supports hooks, I have only been exposed to the ones from Git and have used them - hence this blog post.&lt;br /&gt;
&lt;br /&gt;
Git comes with some predefined hooks that one can use as a starting point. The code is checked before it is being committed and if it does pass whatever the pre-commit (for instance) hook does, it will allow you to commit; alternatively it will stop until you correct the mistakes made.&lt;br /&gt;
&lt;br /&gt;
One very popular pre-commit hook is the one &lt;a href="https://github.com/ReekenX/git-php-syntax-checker"&gt;here&lt;/a&gt; by Remigijus Jarmalavičius. It checkes the files that have been modified/added and runs the php -l on it to ensure that whatever will be committed does not have PHP syntax errors.&lt;br /&gt;
&lt;br /&gt;
I have downloaded that code and easily added it to my repository so everything is being checked prior to any of my commits.&lt;br /&gt;
&lt;br /&gt;
In our &lt;a href="http://www.memberfuse.com/"&gt;MemberFuse™&lt;/a&gt; platform, we have - like any other developer - many helper functions that are used solely for development. One of the mostly used one is the vdd($message); Effectively what this function does is a var_dump of the $message variable, echoes out the file that it was called as well as the line it is in, and dies. It is great for quick and dirty debugging and inspecting a variable as it passes through the code. Granted it is not very TDD but I am sure that all developers have little things like these to aid them with their daily programming and debugging.&lt;br /&gt;
&lt;br /&gt;
From time to time, as we fix bugs and explore certain behaviors that sometimes it is difficult to assess, we use this function and we output the data on the browser. However this is just a development/debugging function and must never be used in the production environment.&lt;br /&gt;
&lt;br /&gt;
I have been the culprit of using the function, forgot that I had it in a certain part of the code, and committed that code in our development branch. That caused some colleagues to experience inconsistent behavior with errors showing up on the screen and time was wasted.&lt;br /&gt;
&lt;br /&gt;
To combat this scenario, I wrote a pre-commit hook that will allow you to check for the existence of certain functions in the code and ensure that those functions (or strings for that matter since I am using &lt;a href="http://en.wikipedia.org/wiki/Grep"&gt;grep&lt;/a&gt;) do not exist in what is to be committed.&lt;br /&gt;
&lt;br /&gt;
The pre-commit hook that I wrote is listed below and the code has been heavily based on &lt;span style="background-color: transparent;"&gt;Remigijus Jarmalavičius's &lt;a href="https://github.com/ReekenX/git-php-syntax-checker"&gt;pre-commit syntax checker&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:bash"&gt;#!/bin/bash
# Author: Nikolaos Dimopoulos &lt;nikos@niden.net&gt;
# Based on code by Remigijus Jarmalavičius &lt;remigijus@jarmalavicius.lt&gt; 
# Checks the files to be committed for the presence of print_r(), var_dump(), die()
# The array below can be extended for further checks

checks[1]="var_dump("
checks[2]="print_r("
checks[3]="die"

element_count=${#checks[@]}
let "element_count = $element_count + 1"

ROOT_DIR="$(pwd)/"
LIST=$(git status | grep -e '\#.*\(modified\|added\)')
ERRORS_BUFFER=""
for file in $LIST
do
    if [ "$file" == '#' ]; then
        continue
    fi
    if [ $(echo "$file" | grep 'modified') ]; then
        FILE_ACTION="modified"
    elif [ $(echo "$file" | grep 'added') ]; then
        FILE_ACTION="added"
    else 
        EXTENSION=$(echo "$file" | grep ".php$")
        if [ "$EXTENSION" != "" ]; then

            index=1
            while [ "$index" -lt "$element_count" ]
            do
                echo "Checking $FILE_ACTION file: $file [${checks[$index]}]" 
                ERRORS=$(grep "${checks[$index]}" $ROOT_DIR$file &amp;gt;&amp;amp;1)
                if [ "$ERRORS" != "" ]; then
                    if [ "$ERRORS_BUFFER" != "" ]; then
                        ERRORS_BUFFER="$ERRORS_BUFFER\n$ERRORS"
                    else
                        ERRORS_BUFFER="$ERRORS"
                    fi
                    echo "${checks[$index]} found in file: $file "
                fi
                let "index = $index + 1"
            done
        fi
    fi
done
if [ "$ERRORS_BUFFER" != "" ]; then
    echo 
    echo "These errors were found in try-to-commit files: "
    echo -e $ERRORS_BUFFER
    echo 
    echo "Can't commit, fix errors first."
    exit 1
else
    echo "Commited successfully."
fi
&lt;/remigijus@jarmalavicius.lt&gt;&lt;/nikos@niden.net&gt;&lt;/pre&gt;
&lt;br /&gt;
If you want to check for any kind of string, just add one extra line (or modify the existing ones) of the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;checks&lt;/span&gt; array. The code will loop through the array and 'grep' the modified/added files for that entry. If it is found the commit will not be allowed and you will have to manually go and change whatever needs to be changed.&lt;br /&gt;
&lt;br /&gt;
I hope you find this hook useful. You can download the file from my &lt;a href="https://github.com/niden/Git-Pre-Commit-Hook-for-certain-words"&gt;github repository&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Note&lt;/b&gt;: If you wish to run more than one pre-commit hooks, you don't need to merge them all in the same file. You can create a pre-commit file which will have the following contents:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:bash"&gt;#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &amp;amp;&amp;amp; pwd )"

$DIR/pre-commit.l
$DIR/pre-commit.output

&lt;pre&gt;&lt;/pre&gt;
&lt;/pre&gt;
The *.l file is the one that runs the PHP syntax check, while the *.output one is the one mentioned in this blog post. You can extend the list to your liking and usage.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-21020081014996638?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/I3Dzf2UKCK0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/21020081014996638/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/11/git-pre-commit-another-check-to-ensure.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/21020081014996638?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/21020081014996638?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/I3Dzf2UKCK0/git-pre-commit-another-check-to-ensure.html" title="Git pre-commit - Another check to ensure clean code [How-To]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-9aU96_99ZbE/TsAeRgLvRdI/AAAAAAAAGkU/FwdPWCvLFUQ/s72-c/git-logo.png" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/11/git-pre-commit-another-check-to-ensure.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMAR345eSp7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-9126896630390907927</id><published>2011-11-11T11:11:00.000-05:00</published><updated>2011-11-11T15:14:06.021-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T15:14:06.021-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><category scheme="http://www.blogger.com/atom/ns#" term="Update" /><title>New beginnings – sleep(6566400) [Personal][Update]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-3S214dx8LTA/Tr1uVH87WjI/AAAAAAAAFu0/21RSIwRGjjc/s1600/update.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="283" src="http://4.bp.blogspot.com/-3S214dx8LTA/Tr1uVH87WjI/AAAAAAAAFu0/21RSIwRGjjc/s320/update.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
It has been a very long time since I last blogged.&lt;br /&gt;
&lt;br /&gt;
The primary reason is that I have been busy and somewhat lazy. Hopefully that trend (the laziness) will not last that much and I will be able to post in higher frequency.
&lt;br /&gt;
&lt;br /&gt;
The biggest update for me came this July. I was actively searching for a new employment opportunity for quite some time, but due to the current market situation, it has been a really difficult task.&lt;br /&gt;
&lt;br /&gt;
In July I received (and accepted) an offer from &lt;a href="http://www.avectra.com/"&gt;Avectra Inc.&lt;/a&gt; I am now a PHP developer for &lt;a href="http://www.memberfuse.com/"&gt;MemberFuse™&lt;/a&gt;, a professional networking application that integrates with the client's association management software and builds an online community for that client.
&lt;br /&gt;
&lt;br /&gt;
My colleagues and I are programming in PHP using a frameworks such as &lt;a href="http://www.doctrine-project.org/"&gt;Doctrine&lt;/a&gt;, &lt;a href="http://framework.zend.com/"&gt;Zend Framework&lt;/a&gt;, &lt;a href="http://www.smarty.net/"&gt;Smarty&lt;/a&gt; and &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; on the client side. The application we produce is offered as SAAS (Software As A Service) and we have well over 1 million users.&lt;br /&gt;
&lt;br /&gt;
Although adjusting to the new environment was rough and the learning curve was steep (it didn't help that one colleague decided to resign and I inherited his workload from week 2), I managed to 'survive' and I am more and more confident every day.&lt;br /&gt;
&lt;br /&gt;
I can only say that working with smart people that push you to excel is a blessing!&lt;br /&gt;
&lt;br /&gt;
The second update is this blog's location. With the introduction of the new dynamic templates in Blogger, I decided to move from Wordpress (and my personal installation for my blog) to Blogger.&lt;br /&gt;
&lt;br /&gt;
The downside was that Blogger could not import my blog. I would always get errors when trying to upload the XML file and after a few tries I decided to go the manual way. I therefore sat down and copied and pasted all the content that I had posted in the past to the new platform.&lt;br /&gt;
&lt;br /&gt;
Luckily it was not a very difficult task, but it was time consuming. Last night I managed to finish everything and write this blog post.&lt;br /&gt;
&lt;br /&gt;
With this move unfortunately I lost all the comments on my posts and I am sure that there will be some broken links here and there but in the end it will all work out.&lt;br /&gt;
&lt;br /&gt;
It was my intention to post this message today (11-11-11) at 11:11 but I kinda messed up the scheduling &amp;nbsp;so the post is being posted a few hours later.&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-9126896630390907927?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/C8MjS-Qx4A8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/9126896630390907927/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/11/new-beginnings-sleep6566400.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/9126896630390907927?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/9126896630390907927?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/C8MjS-Qx4A8/new-beginnings-sleep6566400.html" title="New beginnings – sleep(6566400) [Personal][Update]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-3S214dx8LTA/Tr1uVH87WjI/AAAAAAAAFu0/21RSIwRGjjc/s72-c/update.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/11/new-beginnings-sleep6566400.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YEQX87fCp7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-8166191078739771994</id><published>2011-05-18T14:49:00.000-04:00</published><updated>2011-11-11T14:51:40.104-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T14:51:40.104-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Gentoo" /><category scheme="http://www.blogger.com/atom/ns#" term="Linux" /><category scheme="http://www.blogger.com/atom/ns#" term="Portage" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><title>Using autounmask to Unmask Packages in Gentoo [How-To][Gentoo]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-1OZGvZ5rtP4/Tr18np_OHhI/AAAAAAAAFww/I6sVo1bD_7o/s1600/gentoo.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-1OZGvZ5rtP4/Tr18np_OHhI/AAAAAAAAFww/I6sVo1bD_7o/s1600/gentoo.png" /&gt;&lt;/a&gt;&lt;/div&gt;
Gentoo is one of my favorite Linux distributions. Although I am comfortable with other distributions, Gentoo has a special place in my heart and whenever I can use it I do :)
&lt;br /&gt;
&lt;br /&gt;
There are however some times that I would like to install a package - mostly to test something - and the package is masked. Masked packages are not "production ready" so they are not included in the portage tree i.e. available to be installed.
&lt;br /&gt;
&lt;br /&gt;
To allow a masked package to be installed, you will need to unmask that package by adding a corresponding entry in the etc/portage/package.keywords file.
&lt;br /&gt;
&lt;br /&gt;
The problem happens when the masked package (that you just unmasked) depends on other packages that are also masked. You will then need to rinse and repeat the process to ensure that everything is in place so that you can install that unmasked package.
&lt;br /&gt;
&lt;blockquote&gt;
&lt;strong&gt;NOTE: Playing with masked packages is like playing with fire. If you don't know what you are doing or you are not ready to potentially have an unusable system, don't follow the instructions below or unmask any packages.&lt;/strong&gt;&lt;/blockquote&gt;
&lt;span style="background-color: transparent;"&gt;&lt;b&gt;app-portage/autounmask&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent;"&gt;The Gentoo developers have created a little utility that will unmask each package that needs to be unmasked. The utility is &lt;/span&gt;&lt;strong style="background-color: transparent;"&gt;app-portage/autounmask&lt;/strong&gt;&lt;span style="background-color: transparent;"&gt;.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
I wanted to unmask www-misc/fcgiwrap so my manual method would be:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash"&gt;echo "=www-misc/fcgiwrap ~amd64" &amp;gt;&amp;gt; /etc/portage/packages.keywords&lt;/pre&gt;
&lt;br /&gt;
and would then emerge the package
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash"&gt;emerge =www-misc/fcgiwrap&lt;/pre&gt;
&lt;br /&gt;
Instead I used autounmask:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash"&gt;emerge app-portage/autounmask&lt;/pre&gt;
&lt;br /&gt;
and
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash"&gt;autounmask www-misc/fcgiwrap-1.0.3

autounmask version 0.27 (using PortageXS-0.02.09 and portage-2.1.9.42)
* Using repository: /usr/portage
* Using package.keywords file: /etc/portage/package.keywords&amp;nbsp;* Using package.unmask file: /etc/portage/package.unmask&amp;nbsp;* Using package.use file: /etc/portage/package.use
* Unmasking www-misc/fcgiwrap-1.0.3 and its dependencies.. this might take a while..
* Added '=www-misc/fcgiwrap-1.0.3 ~amd64' to /etc/portage/package.keywords&amp;nbsp;* done!&lt;/pre&gt;
&lt;br /&gt;
Once that is done I can issue the emerge command and voila!
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash"&gt;emerge www-misc/fcgiwrap&lt;/pre&gt;
&lt;br /&gt;
Although in my case there was only one dependency to unmask, when trying to unmask packages that have multiple dependencies such as gnome, kde etc., autounmask can be a very helpful utility.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-8166191078739771994?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/J1jcog_W3x4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/8166191078739771994/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/05/using-autounmask-to-unmask-packages-in.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/8166191078739771994?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/8166191078739771994?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/J1jcog_W3x4/using-autounmask-to-unmask-packages-in.html" title="Using autounmask to Unmask Packages in Gentoo [How-To][Gentoo]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-1OZGvZ5rtP4/Tr18np_OHhI/AAAAAAAAFww/I6sVo1bD_7o/s72-c/gentoo.png" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/05/using-autounmask-to-unmask-packages-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4FRXc6eyp7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-2273927751238789661</id><published>2011-04-21T14:45:00.000-04:00</published><updated>2011-11-11T14:48:34.913-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T14:48:34.913-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Linux" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><category scheme="http://www.blogger.com/atom/ns#" term="Ubuntu" /><category scheme="http://www.blogger.com/atom/ns#" term="Upgrade" /><category scheme="http://www.blogger.com/atom/ns#" term="LibreOffice" /><title>LibreOffice Auto Update [How-To][Linux]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-Hl6wkIBMeL4/Tr174qhF0vI/AAAAAAAAFwo/b1Pmc_E83qo/s1600/libreoffice-3.3RC.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="102" src="http://2.bp.blogspot.com/-Hl6wkIBMeL4/Tr174qhF0vI/AAAAAAAAFwo/b1Pmc_E83qo/s320/libreoffice-3.3RC.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
We all knew it was coming. Ever since &lt;a href="http://www.oracle.com/"&gt;Oracle&lt;/a&gt; took a really surprising turn towards the non-community orientation of &lt;a href="http://www.openoffice.org/"&gt;OpenOffice&lt;/a&gt;, a lot of users on the Internet were curious (and concerned) as to what will happen with the whole OpenOffice saga.
&lt;br /&gt;
&lt;br /&gt;
Thankfully the project was forked and &lt;a href="http://www.libreoffice.org/"&gt;LibreOffice&lt;/a&gt; was born. Within a few months the same (and better) quality product was released for the community. As the project entered its alpha stage, then the beta stage and then the RC stages, I was waiting anxiously to install it on my notebook (which is running &lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt; 10.10 at the moment).
&lt;br /&gt;
&lt;br /&gt;
A couple of months ago, I was finally happy with the package and the release, so I downloaded it on my notebook and started the installation. I don't have a problem with getting my hands dirty and working with the command prompt, but I am lazy - so I want my packages to update easily (say though the package manager). At the time I could not use the package manager, so it was all terminal work :)
&lt;br /&gt;
&lt;br /&gt;
The installation was pretty easy using the &lt;strong&gt;dpkg&lt;/strong&gt; command. I run literally two commands and the application was installed :)
&lt;br /&gt;
&lt;br /&gt;
There was a recent announcement about OpenOffice from Oracle. I posted a link at &lt;a href="http://news.ycombinator.com/item?id=2451079"&gt;HackerNews&lt;/a&gt; for an article I read in MarketWire, regarding this "&lt;em&gt;Oracle to move OpenOffice.org to a Community-Based Project&lt;/em&gt;". Unfortunately the link does not work any more but you might be able to read a bit about the subject &lt;a href="http://www.pcworld.com/businesscenter/article/225459/oracles_openoffice_move_may_be_too_little_too_late.html"&gt;here&lt;/a&gt;. In short:
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;em&gt;OpenOffice is dead, long live LibreOffice&lt;/em&gt;.&lt;/div&gt;
&lt;br /&gt;
Time for me to start getting serious about updating LibreOffice.
&lt;br /&gt;
&lt;br /&gt;
First of all I wanted to make sure that I did not have any cruft remaining from OpenOffice on my system.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;sudo apt-get remove openoffice*.*&lt;/pre&gt;
&lt;br /&gt;
Surprisingly there were some packages that were still there.
&lt;br /&gt;
&lt;br /&gt;
The second step was to uninstall the current version of LibreOffice
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;sudo apt-get remove libreoffice*.*&lt;/pre&gt;
&lt;br /&gt;
And now comes the easy part. I am going to use a PPA, to ensure that I will get notified about pending updates and upgrade easily. To do so all I had to do was run the following commands on a terminal window:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;sudo add-apt-repository ppa:libreoffice/ppa&lt;/pre&gt;
&lt;br /&gt;
Output:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;Executing: gpg --ignore-time-conflict --no-options --no-default-keyring
--secret-keyring /etc/apt/secring.gpg --trustdb-name /etc/apt/trustdb.gpg
--keyring /etc/apt/trusted.gpg --primary-keyring /etc/apt/trusted.gpg
--keyserver keyserver.ubuntu.com --recv 36E81C9267FD1383FCC4490983FBA1751378B444gpg:
requesting key 1378B444 from hkp server keyserver.ubuntu.com
gpg: key 1378B444: public key "Launchpad PPA for LibreOffice Packaging" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; imported: 1 &amp;nbsp;(RSA: 1)&lt;/pre&gt;
&lt;br /&gt;
Then update the packages again:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;sudo apt-get update&lt;/pre&gt;
&lt;br /&gt;
And now install LibreOffice:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;sudo apt-get install libreoffice
sudo apt-get install libreoffice-gnome&lt;/pre&gt;
&lt;br /&gt;
Note: KUbuntu users will need to run
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;sudo apt-get install libreoffice-kde&lt;/pre&gt;
&lt;br /&gt;
For those that prefer the graphical interface, all you will have to do is add "ppa:libreoffice/ppa" to your software sources.
&lt;br /&gt;
&lt;br /&gt;
Enjoy your LibreOffice installation!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-2273927751238789661?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/Eb_Xsr7Doyw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/2273927751238789661/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/04/libreoffice-auto-update-how-tolinux.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/2273927751238789661?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/2273927751238789661?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/Eb_Xsr7Doyw/libreoffice-auto-update-how-tolinux.html" title="LibreOffice Auto Update [How-To][Linux]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-Hl6wkIBMeL4/Tr174qhF0vI/AAAAAAAAFwo/b1Pmc_E83qo/s72-c/libreoffice-3.3RC.png" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/04/libreoffice-auto-update-how-tolinux.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkAHQH89fyp7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-1174702717697844693</id><published>2011-04-04T14:41:00.000-04:00</published><updated>2011-11-11T14:45:31.167-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T14:45:31.167-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Hosting" /><category scheme="http://www.blogger.com/atom/ns#" term="Series" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><category scheme="http://www.blogger.com/atom/ns#" term="HA" /><title>Building a HA Cluster on Linode [How-To][HA][Linux][Series]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-bYOhqaAnq5w/Tr17S7nW2kI/AAAAAAAAFwg/whtxx9Pf5N8/s1600/high_vailability.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="164" src="http://4.bp.blogspot.com/-bYOhqaAnq5w/Tr17S7nW2kI/AAAAAAAAFwg/whtxx9Pf5N8/s320/high_vailability.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
I have recently blogged about &lt;a href="http://www.niden.net/2011/03/slicehost-vs-linode/"&gt;Slicehost vs. Linode&lt;/a&gt; and my decision to move my sites to the latter. Since then I can safely say that I made the right choice about the move. &lt;a href="http://l.niden.net/linode"&gt;Linode&lt;/a&gt;'s support is phenomenal. There has never been a ticket unanswered more than 5 minutes and all the tickets have been resolved. Even when I asked about a configuration issue regarding Heartbeat, which was clearly not in the realm of support, the support engineers did look at my configuration and did identify the error area. That alone saved me hours of troubleshooting and trying to find where the error was.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Task
&lt;/b&gt;&lt;br /&gt;
&lt;span style="background-color: transparent;"&gt;Your website must be available - all the time. Why? Because if you have something to say (a blog, a journal, a rant page, a forum etc.) you need your audience to be able to read your material all the time. Discussion forums, websites with custom applications or services, even information based websites need to have as close to 100% uptime as possible.. How can this be achieved? The solution is a High Availability (or HA) cluster.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Linux has been used for HA tasks for many years. The &lt;a href="http://www.linux-ha.org/wiki/Main_Page"&gt;Linux-HA&lt;/a&gt;'s wiki has a lot of valuable information as well as guides and resources that one can use to increase the redundancy of their websites. In addition to this, Google is your friend. There are numerous bloggers that have shared their experiences with the public on how to create HA resources. Finally, one can check Linode's &lt;a href="http://library.linode.com/"&gt;Library&lt;/a&gt; - a set of guides to allow you to create HA clusters with your Linodes.
&lt;br /&gt;
&lt;br /&gt;
My task for the last few weeks has been to create a High Availability cluster of services to serve PHP and MySQL and also have the ability to grow infinitely (well close to that is). In the next few weeks I will post a series of blog posts outlining how to achieve a HA cluster for your sites.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Architecture
&lt;/b&gt;&lt;br /&gt;
&lt;span style="background-color: transparent;"&gt;The cluster will be build using CentOS as the OS of choice. I have also experimented with Gentoo and Ubuntu. You can do everything I do here with Ubuntu if you wish. There are slight differences in certain commands and steps which the blog posts will not cover. As far as Gentoo is concerned, at the moment there is a block between Pacemaker and Heartbeat. Once that is resolved, I will try to redo the whole thing using Gentoo - as it is my OS of preference.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
We will build two boxes to serve as load balancers. The boxes (or Linodes) will have Heartbeat, Pacemaker and nginx installed on them. A "floating" IP address will be used to move from one node to another in the case of a failure. Each Linode uses nginx as a proxy to forward all requests to a set of web servers using nginx's proxy functionality.
&lt;br /&gt;
&lt;br /&gt;
We will also build a web server. This again is a CentOS box running PHP and nginx. The web server will store the data locally and connect to the database cluster. Once the last part of this How-To is completed (creation of a HA NFS) then we will be able to add as many web servers as we need.
&lt;br /&gt;
&lt;br /&gt;
The next set of boxes form the database cluster. The setup is two servers with Heartbeat, Pacemaker and MySQL setup with a Master/Master replication. Again a "floating" IP address is used to move from one server to another in the case of failure.
&lt;br /&gt;
&lt;br /&gt;
The NFS is also a 2 box setup. Again a "floating" IP address is used to connect to the file system. &lt;a href="http://www.drbd.org/"&gt;DRBD&lt;/a&gt; is installed on them to cater for the replication.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Administration
&lt;/b&gt;&lt;br /&gt;
&lt;span style="background-color: transparent;"&gt;All Linodes are located in the same data center. At the moment there is no way to create Linodes in different data centers and implement the above mentioned setup in an effort to achieve geographical redundancy.&amp;nbsp;The whole setup is using 9 Linodes the last one being used for administrative tasks (note in my count I used 2 boxes as web servers).&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
All Linodes have active iptables configurations. All nodes have been configured to work with 322 as the SSH port to avoid the novice hacker. Every port is blocked from communicating with the Internet apart from the ones needed for essential services. For instance the Load Balancers allow connections on ports 80 and 443 (http and https). However, they only communicate with each other on the Heartbeat port. Equally the web servers do not allow connections to their 80/443 ports to any machine other than the Load Balancers. The Database Servers allow connections only from the Web servers etc.
&lt;br /&gt;
&lt;br /&gt;
The administrative node resides on a different data center. It runs Nagios and it monitors all the nodes of our HA cluster. Naturally the iptables setup of each node is adjusted to allow connections from this particular node.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion
&lt;/b&gt;&lt;br /&gt;
&lt;span style="background-color: transparent;"&gt;I hope that these blog posts will serve as a learning exercise/guide to those who want to delve in High Availability websites. The primary reason I built this cluster is to offer these services to customers that have busy sites that require maximum availability. I am currently setting up the final touches of the hosting service I am going to offer so stay tuned for the details.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;Disclaimer: The Linode link in this blog post is an affiliate one. If you wish to sign up for their services you are more than welcome to click it. The non affiliate link is &lt;a href="https://manager.linode.com/signup/"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-1174702717697844693?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/P7vfasO9-dQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/1174702717697844693/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/04/building-ha-cluster-on-linode-how.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/1174702717697844693?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/1174702717697844693?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/P7vfasO9-dQ/building-ha-cluster-on-linode-how.html" title="Building a HA Cluster on Linode [How-To][HA][Linux][Series]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-bYOhqaAnq5w/Tr17S7nW2kI/AAAAAAAAFwg/whtxx9Pf5N8/s72-c/high_vailability.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/04/building-ha-cluster-on-linode-how.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YDSH0_fSp7ImA9WhRSEE4.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-8210677066514343368</id><published>2011-03-21T14:10:00.000-04:00</published><updated>2011-11-11T14:19:39.345-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T14:19:39.345-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Gentoo" /><category scheme="http://www.blogger.com/atom/ns#" term="Linux" /><category scheme="http://www.blogger.com/atom/ns#" term="Hosting" /><category scheme="http://www.blogger.com/atom/ns#" term="Information" /><category scheme="http://www.blogger.com/atom/ns#" term="VPS" /><title>Slicehost vs. Linode [Hosting][VPS]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-r1mM0nbKiuk/Tr10IXu7JSI/AAAAAAAAFwI/OtambY19bQg/s1600/VPS.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-r1mM0nbKiuk/Tr10IXu7JSI/AAAAAAAAFwI/OtambY19bQg/s1600/VPS.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
Through the years I have hosted my sites on various hosting companies. I had the really good experiences like &lt;a href="http://www.vertexhost.com/"&gt;Vertexhost&lt;/a&gt; and really terrible ones - I don't remember the name of the host, but that kid, as it turned out to be later on, managed to lose 1.6GB of my data. You can safely say that I have been burned by bad hosting companies but also have enjoyed the services of good ones. In the case of &lt;a href="http://www.vertexhost.com/"&gt;Vertexhost&lt;/a&gt;, I part owned that company a few years back and I know that the current owner is a straight up guy and really cares for his customers.
&lt;br /&gt;
&lt;br /&gt;
Since I moved my emails to &lt;a href="http://www.google.com/a/"&gt;Google Apps&lt;/a&gt; I only need the hosting for my personal sites such as my blog, my wife's sites (&lt;a href="http://www.burntoutmom.com/"&gt;burntoutmom.com&lt;/a&gt;, &lt;a href="http://www.greekmommy.net/"&gt;greekmommy.net&lt;/a&gt;) and a few other small sites.
&lt;br /&gt;
&lt;br /&gt;
I used to host those sites on one of my company's clusters. The bandwidth consumed was nothing to write home about (I think in total it was a couple of GB per month ~ 1.00 USD) so it didn't matter that I had them there. However, recent events forced me to move them out of that cluster. I was on the market for good and relatively cheap hosting. I did not want to purchase my own server or colocate with someone else. My solution was going to be a VPS since I would be in control of what I install and what I need.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Slicehost
&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-wrQI3rybbMk/Tr10PKB6C0I/AAAAAAAAFwQ/eeYtZ_2XxN8/s1600/slicehostLogo.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-wrQI3rybbMk/Tr10PKB6C0I/AAAAAAAAFwQ/eeYtZ_2XxN8/s1600/slicehostLogo.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Without much thought, I signed up for &lt;a href="http://www.slicehost.com/"&gt;Slicehost&lt;/a&gt;, which is a&amp;nbsp;subsidiary of &lt;a href="http://www.rackspace.com/"&gt;Rackspace&lt;/a&gt;, a very well known and reputable company.
&lt;br /&gt;
&lt;br /&gt;
I got their 4GB package (250.00 USD per month) and installed &lt;a href="http://www.gentoo.org/"&gt;Gentoo&lt;/a&gt; on it. Apart from the price which was a bit steep, everything else was fine. I was happy to be able to host my sites in a configuration that I was comfortable with, under the understanding that if the VPS failed, then all my sites would go down. That however is the risk that everyone takes while hosting their sites on a single machine. The higher the availability and redundancy the higher the cost.
&lt;br /&gt;
&lt;br /&gt;
I must admit that signing up was not a very happy experience. I went and paid with my credit card, as they pro-rate your month based on your package. Almost immediately after signing up, came the email informing me that my credit card has been charged for the relevant amount. I got into the box through ssh, updated the &lt;i&gt;/etc/make.conf&lt;/i&gt; file with the USE flags that I needed, run &lt;i&gt;emerge --sync&lt;/i&gt; and then &lt;i&gt;emerge --update --deep --newuse --verbose world&lt;/i&gt; so as to update the system.
&lt;br /&gt;
&lt;br /&gt;
It must have been around 5-10 minutes into the process that I received an email from Slicehost saying that they are checking my account information and that I need to confirm my credit card details. I immediately replied to their email (gotta love the desktop notifications on GMail), with the information they needed.
&lt;br /&gt;
&lt;br /&gt;
After I sent the email, I noticed that the box was not responding. I tried to log back in and could not. I was also logged out (and could not log back in) to their management console on slicehost.com site. I was fuming! Effectively they severed the connection to the VPS in the middle of compilation to check my credit card information.I understand that they need to perform checks for fraud but two questions came to mind:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Why did they have to sever the connection and not just send an email, and if I did not reply, just block access to the box? That would have been a heck of a lot of an inconvenience to myself i.e. the end user.&lt;/li&gt;
&lt;li&gt;Why did the initial email say that my credit card has been charged and it had not?&lt;/li&gt;
&lt;/ol&gt;
No more than 10 minutes later the whole thing had been resolved. I received an email saying that "&lt;i&gt;everything is OK and your account has been restored"&lt;/i&gt;, at which point I logged back in to redo the compilations. I also received emails from their support/billing team apologizing but stating that although the initial email states that they charge the credit card, they don't. It is something they need to correct because it pisses people (like me) off.
&lt;br /&gt;
&lt;br /&gt;
There was nothing wrong with my setup - everything was working perfectly but the price was really what was bothering me. I would be able to support the sites for a few months, but since literally none of them is making money (maybe a dollar here or there from my blog but that is about it), I would have to pay out of pocket for the hosting every month. I had to find a different solution that would be:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;cheaper than Slicehost&lt;/li&gt;
&lt;li&gt;flexible in terms of setup&lt;/li&gt;
&lt;li&gt;easy to use in terms of controlling your VPS&lt;/li&gt;
&lt;/ul&gt;
After a lot of research I ended up with two winners: &lt;a href="http://l.niden.net/linode"&gt;Linode&lt;/a&gt; and &lt;a href="http://www.prgmr.com/"&gt;Prgmr&lt;/a&gt;. I opted for Linode, because although it was quite a bit more expensive than Prgmr, it had the better console in handling your VPS. I will, however, try out Prgmr's services in the near future so as to assess how good they are. They definitely cannot be beat in price.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Linode
&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-H4uCFgYjyOQ/Tr10gJMZB0I/AAAAAAAAFwY/z2H5iqeODR8/s1600/linode.gif" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-H4uCFgYjyOQ/Tr10gJMZB0I/AAAAAAAAFwY/z2H5iqeODR8/s1600/linode.gif" /&gt;&lt;/a&gt;&lt;/div&gt;
Setting up an account with Linode was very easy. I didn't have any of the mini-saga I had with Slicehost. The account was created right there and then, my credit card charged and I was up and running in no time. Immediately I could see a difference in price. Linode's package for 4GB or RAM is 90.00 USD cheaper (159.00 USD vs. 250.00 USD for Slicehost). For the same package, the price difference is huge.&lt;br /&gt;
&lt;br /&gt;
I started testing the network, creating my VPS in the Atlanta, GA datacenter (Linode offers a number of datacenters for you to create your own). The functionality that was available to me was identical and in some cases superior to that of Slicehost. There are a lot more distributions to choose from, and you can partition your VPS the way you want it to name a couple.
&lt;br /&gt;
&lt;br /&gt;
Shifting through the &lt;a href="http://library.linode.com/"&gt;documentation&lt;/a&gt;, I saw a few topics regarding high availability websites. The articles described using &lt;a href="http://www.drbd.org/"&gt;DRBD&lt;/a&gt;, &lt;a href="http://nginx.org/"&gt;nginx&lt;/a&gt;, &lt;a href="http://www.linux-ha.org/wiki/Main_Page"&gt;heartbeat&lt;/a&gt; and pacemaker etc. to keep your sites highly available. I was intrigued by the information and set off to create a load balancer using two VPSs and nginx. I have documented the process and this is another blog post that will come later on this week.
&lt;br /&gt;
&lt;br /&gt;
While experimenting with the load balancer (and it was Saturday evening) I had to add a new IP address to one of the VPS instances. At the time my account would not allow such a change and I had to contact support. I did and got a reply in less than 5 minutes. I was really impressed by this. Subsequent tickets were answered within the 5 minute time frame. Kudos to Linode support for their speed and professionalism.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion
&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
For a lot cheaper, Linode offered the same thing that Slicehost did. Moving my sites from one VPS to another was a matter of changing my DNS records to point &amp;nbsp;to the new IP address.
&lt;br /&gt;
&lt;br /&gt;
I have been using Linode for a week and so far so good. The support is superb and the &lt;a href="http://library.linode.com/"&gt;library&lt;/a&gt; is full of how-to's that allows me to experiment with anything I want to - and the prices are not going to break me.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Resources
&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.vertexhost.com/"&gt;Vertexhost&lt;/a&gt;,&amp;nbsp;&lt;a href="http://www.slicehost.com/"&gt;Slicehost&lt;/a&gt;,&amp;nbsp;&lt;a href="http://www.rackspace.com/"&gt;Rackspace&lt;/a&gt;,&amp;nbsp;&lt;a href="http://www.gentoo.org/"&gt;Gentoo&lt;/a&gt;,&amp;nbsp;&lt;a href="http://l.niden.net/linode"&gt;Linode&lt;/a&gt;,&amp;nbsp;&lt;a href="http://library.linode.com/"&gt;Linode Library&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-8210677066514343368?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/0eBsbgq0v_w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/8210677066514343368/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/03/slicehost-vs-linode-hostingvps.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/8210677066514343368?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/8210677066514343368?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/0eBsbgq0v_w/slicehost-vs-linode-hostingvps.html" title="Slicehost vs. Linode [Hosting][VPS]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-r1mM0nbKiuk/Tr10IXu7JSI/AAAAAAAAFwI/OtambY19bQg/s72-c/VPS.jpg" height="72" width="72" /><thr:total>2</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/03/slicehost-vs-linode-hostingvps.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkIMR3s8eip7ImA9WhRSEE4.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-4768088655361555102</id><published>2011-03-10T14:00:00.000-05:00</published><updated>2011-11-11T14:09:46.572-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T14:09:46.572-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Review" /><category scheme="http://www.blogger.com/atom/ns#" term="Docs" /><category scheme="http://www.blogger.com/atom/ns#" term="Online Storage" /><category scheme="http://www.blogger.com/atom/ns#" term="Information" /><category scheme="http://www.blogger.com/atom/ns#" term="Google" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Apps" /><category scheme="http://www.blogger.com/atom/ns#" term="Picasa" /><title>Additional storage for Google Apps users [Information][Review]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-mTZTSrlAoVU/Tr1yc7fWhlI/AAAAAAAAFvs/-Xf-jfj6KfY/s1600/google-apps-logo-150x150.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-mTZTSrlAoVU/Tr1yc7fWhlI/AAAAAAAAFvs/-Xf-jfj6KfY/s1600/google-apps-logo-150x150.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
I have been using Google Apps for a number of years now and I have gotten so used to it that I cannot fathom any other way of operating. I am sure that some of you share that sentiment. :)
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Limitations
&lt;/b&gt;&lt;br /&gt;
Up until a few months ago, Google Apps had its limitations. The actual Apps was in some sort of a jailshell, isolated from the whole Google suite of applications. For that reason you could not use your Google Apps login to enjoy the service of Google Reader for instance. You had to be sneaky about it. You had to create a Google Account with the same username (and password if you liked) as your Google Apps domain and although the two did not communicate, you could have effectively "one login" for all services.&lt;br /&gt;
&lt;br /&gt;
This limitation became more apparent with the increased usage of Android phones (where you need to have a Google Account on your phone) as well as Google Voice. Users have been asking about the "merge" and Google responded with significant infrastructure changes to cater for the transition. In my blog post "&lt;a href="http://www.niden.net/2010/08/google-apps-and-google-accounts-merge-information-howto/"&gt;Google Apps and Google Accounts Merge&lt;/a&gt;" I present additional information about this, inclusive of a&amp;nbsp;How-To on the transition for administrators of Google Apps. Unfortunately the process is not perfect and there are still some services that are not fully integrated with the new infrastructure (but will be in the future). For instance in my domain, since I use Google Voice with my domain email account, I am still on the "old" system because the account could not be transitioned. It will happen in the end, it just takes time.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Storage Needs
&lt;/b&gt;&lt;br /&gt;
The biggest issue for me that was related to these two separated accounts (Google Apps Account vs. Google Account) was &lt;a href="http://picasaweb.google.com/nikos.dimopoulos"&gt;Picasa&lt;/a&gt; and &lt;a href="http://docs.google.com/"&gt;Google Docs&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
I have been very methodical in my filing, utilizing electronic storage as much as possible. For that reason I have been scanning documents and uploading them to Google Docs (or if they were available in PDF format I would just upload them). The documents would range from personal, utility bills, bank statements, anything that I want to store. Soon I realized that the 1GB that Google Apps offers for documents will not cut it. I therefore created a new account which I named DocsMule1 (clearly to signify its purpose). I created one folder in that account, uploaded as many documents as I could there and shared that document with my own account as well as my wife's. Soon I found more limitations since I ended up with 3 mule accounts. Since there was no option for me to upgrade the storage (even if I paid for it), I had to change my strategy. Managing documents from 3 or more different accounts is not an easy and convenient task.
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-MuwgFdqwTls/Tr1y0um1RmI/AAAAAAAAFv4/3C8bwvG19bU/s1600/google-manage-storage-300x246.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-MuwgFdqwTls/Tr1y0um1RmI/AAAAAAAAFv4/3C8bwvG19bU/s1600/google-manage-storage-300x246.png" /&gt;&lt;/a&gt;&lt;/div&gt;
I downloaded all my documents back to my computer (gotta love Google's &lt;a href="http://www.dataliberation.org/"&gt;Data Liberation&lt;/a&gt;) and deleted them from the Google Apps mule accounts and then deleted those accounts - just to keep everything tidy. I then launched my Gmail account and signed into Google Docs. I created one folder which I shared with my Google Apps accounts (my wife's and mine) and then paid $50.00 for a whole year - which provided me with 200GB of space. You can always check how much space you are using by visiting the &lt;a href="https://www.google.com/accounts/b/0/ManageStorage"&gt;Manage Storage&lt;/a&gt; page of your Google Account.&lt;br /&gt;
&lt;br /&gt;
Once that was done, I started creating my folders (collections now) and uploaded all my documents up there. In addition to that, since my parents live in Greece, they rely on VoIP chat as well as my Picasa to stay in touch with their grandchildren. My wife and I, through the use of our mini camera as well as our Android phones, take a lot of pictures of the kids, documenting the little things that they do on a regular basis. This serves as a good archive for them when they grow up but also as a good way to stay in touch with my parents. Google's additional storage was the solution.
&lt;br /&gt;
&lt;br /&gt;
Problem solved. With minimal money I had everything sorted out. It did however inconvenience me quite a bit in the end, since a lot of my data was scattered now. The GMail account would keep Picasa and Docs, the Google Apps account my email, my Google account my Reader, Web history etc. &amp;nbsp;Not very convenient but it works.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Storage for Google Apps
&lt;/b&gt;&lt;br /&gt;
Around February, Google announced that they will be offering the option to Google Apps users to purchase additional storage. I was really happy about that since I could therefore ditch the GMail account for handling my docs and keep everything under the domain account. However something was wrong. When Google revealed their pricing (the announcement is not there any more but the prices I am quoting are real), I quickly found out that for the storage I currently have, I would need to spend $700.00 a year instead of $50.00. That did not make sense at all. Needless to say, I stayed with my existing plan.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;b&gt;Initial Pricing Plan
&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre;"&gt; &lt;/span&gt;&lt;strong style="font-family: monospace; white-space: pre;"&gt;Storage&lt;/strong&gt;&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre;"&gt;   &lt;/span&gt;&lt;strong style="font-family: monospace; white-space: pre;"&gt;Price (per year)&lt;/strong&gt;&lt;br /&gt;
&lt;pre&gt;   5 GB         17.50 USD
  20 GB         70.00 USD
  80 GB        280.00 USD
 &lt;strong&gt;200 GB        700.00 USD&lt;/strong&gt;
 400 GB      1,400.00 USD
   1 TB      3,500.00 USD
   2 TB      7,000.00 USD
   4 TB     14,000.00 USD
   8 TB     28,000.00 USD
  16 TB     56,000.00 USD&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;New Pricing Plan
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
A few days ago, Google announced changes in the pricing of additional storage for Google Apps users as well as changes to the free storage that Google offers for Picasa. Picasa Web Albums does offer 1GB of free storage but now photos of 800x800 pixels or less as well as videos of 15 minutes or less do not count against the 1GB of storage. You can read more about the Picasa Web Albums storage in the relevant &lt;a href="http://picasa.google.com/support/bin/answer.py?answer=43879"&gt;help page&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt; &lt;strong&gt;Storage&lt;/strong&gt;   &lt;strong&gt;Price (per year)&lt;/strong&gt;
  20 GB         5.00 USD
  80 GB        20.00 USD
 200 GB        50.00 USD
 400 GB       100.00 USD
   1 TB       256.00 USD
   2 TB       512.00 USD
   4 TB     1,024.00 USD
   8 TB     2,048.00 USD
  16 TB     4,096.00 USD&lt;/pre&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-2qTyhIRHDCc/Tr1y8dF8rAI/AAAAAAAAFwA/SLtOkUsxppM/s1600/google-apps-purchase-storage-300x215.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-2qTyhIRHDCc/Tr1y8dF8rAI/AAAAAAAAFwA/SLtOkUsxppM/s1600/google-apps-purchase-storage-300x215.png" /&gt;&lt;/a&gt;&lt;/div&gt;
As far as the new pricing is concerned, Google brought everything in line with Google Accounts pricing (effectively scrapping the initial - expensive - pricing plan for extra storage). The help page "&lt;a href="http://picasa.google.com/support/bin/answer.py?answer=39567"&gt;Google Storage - How it Works&lt;/a&gt;" offers additional information for those that want to use/upgrade their storage while using a Google Apps account. Effectively&amp;nbsp;it now costs exactly the same to purchase additional space for your Google Apps account (to store documents) as it would if you were using a different Google Account. That probably means that I have to download everything to my computer and &amp;nbsp;re-upload it to my Google Apps account....
&lt;br /&gt;
&lt;br /&gt;
To take advantage of this feature, you will have to go to the &lt;a href="https://www.google.com/accounts/b/0/PurchaseStorage?hl=en_US"&gt;Purchase additional storage&lt;/a&gt; page while logged in with the Google Apps account that you wish to purchase storage for. Note that there is a warning that appears in red (see image) that warns you that you are using a Google Apps account. Google provides this information since your Google Apps account relies on the Google Apps administrator. If you have an account on Google Apps and you purchase storage, that storage will be gone if the administrator deletes or restricts access to your account.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion
&lt;/b&gt;&lt;br /&gt;
In my view, Google has done it again. They now offer an extremely affordable and secure way of storing your data. There are loads of people that have concerns about where their data is stored, who has ownership of the data stored, what does Google do with the data etc. A lot of these questions can easily be answered if you google (duh) the relevant terms or search in &lt;a href="http://www.google.com/support/"&gt;Google's Help Center&lt;/a&gt;. &lt;a href="http://www.dataliberation.org/"&gt;Data Liberation&lt;/a&gt; allows you to retrieve your data whenever you want to. If on the other hand you are skeptical and do not wish to store your data there, don't. It is your choice.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;References
&lt;/b&gt;&lt;br /&gt;
&lt;a href="http://docs.google.com/"&gt;Google Docs&lt;/a&gt;,&amp;nbsp;&lt;a href="http://picasaweb.google.com/"&gt;Picasa Web Albums&lt;/a&gt;,&amp;nbsp;&lt;a href="http://www.dataliberation.org/"&gt;Data Liberation&lt;/a&gt;,&amp;nbsp;&lt;a href="https://www.google.com/accounts/b/0/ManageStorage"&gt;Google Account - Manage Storage&lt;/a&gt;,&amp;nbsp;&lt;a href="http://picasa.google.com/support/bin/answer.py?answer=43879"&gt;Photo and Video Requirements: Size Limits for Picasa Web Albums&lt;/a&gt;,&amp;nbsp;&lt;a href="http://picasa.google.com/support/bin/answer.py?answer=39567"&gt;Google Storage - How it Works&lt;/a&gt;,&amp;nbsp;&lt;a href="https://www.google.com/accounts/b/0/PurchaseStorage?hl=en_US"&gt;Google Account - Purchase additional storage&lt;/a&gt;,&amp;nbsp;&lt;a href="http://www.google.com/support/"&gt;Google's Help Center&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-4768088655361555102?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/4tmxKN-khWE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/4768088655361555102/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/03/additional-storage-for-google-apps.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/4768088655361555102?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/4768088655361555102?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/4tmxKN-khWE/additional-storage-for-google-apps.html" title="Additional storage for Google Apps users [Information][Review]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-mTZTSrlAoVU/Tr1yc7fWhlI/AAAAAAAAFvs/-Xf-jfj6KfY/s72-c/google-apps-logo-150x150.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/03/additional-storage-for-google-apps.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4HQHg6eSp7ImA9WhRSEE4.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-4802713170056069724</id><published>2011-02-20T13:56:00.000-05:00</published><updated>2011-11-11T13:58:51.611-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T13:58:51.611-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="RSync" /><category scheme="http://www.blogger.com/atom/ns#" term="Storage" /><category scheme="http://www.blogger.com/atom/ns#" term="NFS" /><category scheme="http://www.blogger.com/atom/ns#" term="Linux" /><category scheme="http://www.blogger.com/atom/ns#" term="Bash" /><title>Keeping your Linux users in sync in a cluster [How-To][Linux][Sync]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-NdE2r_F0_aE/Tr1vwHhES8I/AAAAAAAAFvE/Iwh6z31EHek/s1600/sync.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-NdE2r_F0_aE/Tr1vwHhES8I/AAAAAAAAFvE/Iwh6z31EHek/s1600/sync.png" /&gt;&lt;/a&gt;&lt;/div&gt;
As websites become more and more popular, your application might not be able to cope with the demand that your users put on your server. To accommodate that, you will need to move out of the one server solution and create a cluster. The easiest cluster to create would be with two servers, one to handle your web requests (HTTP/PHP etc.) and one to handle your database load (MySQL). Again this setup can only get you so far. If your site is growing, you will need a cluster of servers.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Database
&lt;/b&gt;&lt;br /&gt;
The scope of this How-To will not cover database replication; I will need to dedicate a separate blog post for that. However, clustering your database is relatively easy with MySQL replication. You can set a virtual hostname (something like mysql.mydomain.com) which is visible only within your network. You then set up the configuration of your application to use that as the host. The virtual hostname will map to the current master server, while the slave(s) will only replicate.&lt;br /&gt;
&lt;br /&gt;
For instance, if you have two servers A and B, you can configure both of them to become master or slave in MySQL. You then set one of them as master (A) and the other as slave (B). If something happens to A, B gets promoted to master instantly. Once A comes back up, it gets demoted to a slave and the process is repeated if/when B has a problem. This can be a very good solution but you will need to have pretty evenly matched servers to keep with the demand. Alternatively B can be less powered than A and when A comes back up you keep it momentarily as a slave (until everything is replicated) and then promote it back to master.
&lt;br /&gt;
&lt;br /&gt;
One thing to note about replication (that I found through trial and error). MySQL keeps binary logs to handle replication. If you are not cautious in your deployment, MySQL will never recycle those logs and therefore you will soon run out of space when having a busy site. By default those logs will be under &lt;em&gt;/var/lib/mysql&lt;/em&gt;.
&lt;br /&gt;
&lt;br /&gt;
By changing directives in &lt;em&gt;my.cnf&lt;/em&gt; you can store the binary logs in a different folder and even set up 'garbage collection' or recycling. You can for instance set the logs to rotate every X days with the following directive in &lt;em&gt;my.cnf&lt;/em&gt;:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;expire_logs_days &amp;nbsp;= 5&lt;/pre&gt;
&lt;br /&gt;
I set mine to 5 days which is extremely generous. If your replication is broken you must have the means to know about it within minutes (see &lt;a href="http://www.nagios.org/"&gt;nagios&lt;/a&gt; for a good monitoring service). In most cases 2 days is more than enough.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Files
&lt;/b&gt;&lt;br /&gt;
There are numerous ways of keeping your cluster in sync. A really good tool that I have used when playing around with a cluster is &lt;a href="http://oss.linbit.com/"&gt;csync2&lt;/a&gt;. Installation is really easy and and all you will need is to run a cron task every X minutes (up to you) to synchronize the new files. Imagine it as a two way &lt;a href="http://samba.anu.edu.au/rsync/"&gt;rsync&lt;/a&gt;. Another tool that can do this is &lt;a href="http://www.cis.upenn.edu/~bcpierce/unison/"&gt;unison&lt;/a&gt; but I found it to be slow and difficult to implement - that's just me though.&lt;br /&gt;
&lt;br /&gt;
Assume an implementation of a website being served by two (or more) servers behind a load balancer. If your users upload files, you don't know where those files are uploaded, which server that is. As a result if user A uploads the file &lt;em&gt;abc.txt&lt;/em&gt; to server A, user B might be served the content from server B and would not be able to access the file. &lt;a href="http://oss.linbit.com/"&gt;csync2&lt;/a&gt; would synchronize the file across the number of servers, thus providing access to the content and keeping multiple copies of the content (additional backup if you like).
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;NFS
&lt;/b&gt;&lt;br /&gt;
An alternative to keeping everything synchronized is to use a NFS. This approach has many advantages and some disadvantages. It is up to you on whether the disadvantages are something you can live with.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Disadvantages
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;NFS is slow - slower than the direct access to a local hard drive.&lt;/li&gt;
&lt;li&gt;Most likely you will use a symlink to the NFS folder, which can slow things down even more.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;&lt;i&gt;Advantages&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;The NFS does not rely on the individual web servers for content.&lt;/li&gt;
&lt;li&gt;The web servers can be low to medium spec boxes without the need to have really fast and large hard drives&lt;/li&gt;
&lt;li&gt;A well designed NFS with &lt;a href="http://oss.linbit.com/"&gt;DRDB&lt;/a&gt; provides a raid-1 over a network. Using gigabit Network Interface Cards you can keep performance at really high levels.&lt;/li&gt;
&lt;/ul&gt;
I know that my friend &lt;a href="http://www.axivo.com/"&gt;Floren&lt;/a&gt; does not agree with my approach on the NFS and would definitely have gone with the &lt;a href="http://oss.linbit.com/"&gt;csync2&lt;/a&gt; approach. Your implementation depends on your needs.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Users and Groups
&lt;/b&gt;&lt;br /&gt;
Using the NFS approach, we need to keep the files and permissions properly set up for our application. Assume that we have two servers and we need to create one user to access our application and upload files.&lt;br /&gt;
&lt;br /&gt;
The user has been created on both servers and the files are stored on the NFS. Connecting to server A and looking at the files we can see something like this:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;drwxr-xr-x 17 niden  niden  4096 Feb 18 13:41 www.niden.net
drwxr-xr-x  5 niden  niden  4096 Nov 15 22:10 www.niden.net.files
drwxr-xr-x  7 beauty beauty 4096 Nov 21 17:42 www.beautyandthegeek.it
&lt;/pre&gt;
&lt;br /&gt;
However when connecting to server B, the same listing tells another story:&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;drwxr-xr-x 17 508    510    4096 Feb 18 13:41 www.niden.net
drwxr-xr-x  5 508    510    4096 Nov 15 22:10 www.niden.net.files
drwxr-xr-x  7 510    511    4096 Nov 21 17:42 www.beautyandthegeek.it
&lt;/pre&gt;
&lt;br /&gt;
The problem here is the uid and gid of the users and groups of each user respectively. Somehow (and this is really easy to happen) server A had one or more users added to it, thus the internal counter of the user IDs has been increased by one or more and is not identical to that one of server B. So adding a new user in server A will get the uid 510 while on server B the same process will produce a user with a uid of 508.&lt;br /&gt;
&lt;br /&gt;
To have all users setup on all servers the same way, we need to use two commands: &lt;a href="http://man.he.net/man8/groupadd"&gt;groupadd&lt;/a&gt; and &lt;a href="http://man.he.net/man8/useradd"&gt;useradd&lt;/a&gt; (in some Linux distributions you might find them as addgroup and adduser).
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;groupadd
&lt;/b&gt;&lt;br /&gt;
First of all you will need to add groups. You can of course keep all users in one group but my implementation was to keep one user and one group per access. To cater for that I had to first create a group for every user and then the user account itself. Like users, groups have unique ids (gid). The purpose of gid is:&lt;br /&gt;
&lt;blockquote&gt;
The numerical value of the groups ID. This value must be unique, unless the -o option is used. The value must be non-negative. The default is to use the smallest ID value greater than 999 and greater than every other group. Values between 0 and 999 are typically reserved for system accounts.&lt;/blockquote&gt;
I chose to assign each group a unique id (you can&amp;nbsp;override&amp;nbsp;this behavior by using the -o switch in the command below, thus allowing a gid to be used in more than one group). The arbitrary number that I chose was 2000.
&lt;br /&gt;
&lt;br /&gt;
As an example, I will set &lt;em&gt;niden&lt;/em&gt; as the user/group for accessing this site and &lt;em&gt;beauty&lt;/em&gt; as the user/group that accesses &lt;a href="http://www.beautyandthegeek.it/"&gt;BeautyAndTheGeek.IT&lt;/a&gt;. Note that this is only an example.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;groupadd --gid 2000 niden
groupadd --gid 2001 beauty&lt;/pre&gt;
&lt;br /&gt;
Repeat the process as many times as needed for your setup. Connect to the second server and repeat this process. Of course if you have more than two servers, repeat the process on each of the servers that you have (and each accesses your NFS)
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;useradd
&lt;/b&gt;&lt;br /&gt;
The next step is to add the users. Like groups, we will need to set the uid up. The purpose of the uid is:&lt;br /&gt;
&lt;blockquote&gt;
The numerical value of the users ID. This value must be unique, unless the -o option is used. The value must be non-negative. The default is to use the smallest ID value greater than 999 and greater than every other user. Values between 0 and 999 are typically reserved for system accounts.&lt;/blockquote&gt;
Like with the groups, I chose to assign each user a unique id starting from 2000.
&lt;br /&gt;
&lt;br /&gt;
So to in the example above, the commands that I used were:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;useradd --uid 2000 -g niden --create-home niden
useradd --uid 2000 -g beauty --create-home beauty&lt;/pre&gt;
&lt;br /&gt;
You can also use a different syntax, utilizing the numeric gids:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;useradd --uid 2000 --gid 2000 --create-home niden
useradd --uid 2000 --gid 2001 --create-home beauty&lt;/pre&gt;
&lt;br /&gt;
Again, repeat the process as many times as needed for your setup and to as many servers as needed.
&lt;br /&gt;
&lt;br /&gt;
In the example above I issued the --create-home switch (or -m) so as a home folder to be created under /home for each user. Your setup might not need this step. Check the references at the bottom of this blog post for the manual pages for &lt;a href="http://man.he.net/man8/groupadd"&gt;groupadd&lt;/a&gt; and&amp;nbsp;&lt;a href="http://man.he.net/man8/useradd"&gt;useradd&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
I would suggest that you keep a log of which user/group has which uid/gid. It helps in the long run, plus it is a good habit to keep proper documentation on projects :)
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Passwords?
&lt;/b&gt;&lt;br /&gt;
So how about the passwords on all servers? My approach is crude but effective. I connected to the first server, and set the password for each user, writing down what the password was:&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;passwd niden&lt;/pre&gt;
&lt;br /&gt;
Once I had all the passwords set, I opened the /etc/shadow file.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;nano /etc/shadow&lt;/pre&gt;
&lt;br /&gt;
and that revealed a long list of users and their scrambled passwords:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;niden:$$$$long_string_of_characters_goes_here$$$$:13864:0:99999:7:::
beauty:$$$$again_long_string_of_characters_goes_here$$$$:15009:0:99999:7:::&lt;/pre&gt;
&lt;br /&gt;
Since I know that I added niden and beauty as users, I copied these two lines. I then connected to the second server, opened /etc/shadow and located the two lines where the niden and beauty users are referenced. I deleted the existing lines, and pasted the ones that I had copied from server A. Saved the file and now my passwords are synchronized in both servers.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion
&lt;/b&gt;&lt;br /&gt;
The above might not be the best way of keeping users in sync in a cluster but it gives you an idea on where to start. There are different implementations available (Google is your friend) and your mileage might vary. The above has worked for me for a number of years since I never needed to add more than a handful of users on the servers each year.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;References
&lt;/b&gt;&lt;br /&gt;
&lt;a href="http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html"&gt;MySQL System Variables&lt;/a&gt;, &lt;a href="http://www.nagios.org/"&gt;Nagios&lt;/a&gt;, &lt;a href="http://oss.linbit.com/"&gt;csync2&lt;/a&gt;, &lt;a href="http://samba.anu.edu.au/rsync/"&gt;rsync&lt;/a&gt;, &lt;a href="http://www.cis.upenn.edu/~bcpierce/unison/"&gt;Unison File Synchronizer&lt;/a&gt;, &lt;a href="http://oss.linbit.com/"&gt;DRDB&lt;/a&gt;, &lt;a href="http://www.axivo.com/"&gt;Axivo Inc.&lt;/a&gt;, &lt;a href="http://man.he.net/man8/groupadd"&gt;groupadd man page&lt;/a&gt;, &lt;a href="http://man.he.net/man8/useradd"&gt;useradd man page&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-4802713170056069724?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/5lnhk1CUWaU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/4802713170056069724/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/02/keeping-your-linux-users-in-sync-in.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/4802713170056069724?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/4802713170056069724?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/5lnhk1CUWaU/keeping-your-linux-users-in-sync-in.html" title="Keeping your Linux users in sync in a cluster [How-To][Linux][Sync]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-NdE2r_F0_aE/Tr1vwHhES8I/AAAAAAAAFvE/Iwh6z31EHek/s72-c/sync.png" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/02/keeping-your-linux-users-in-sync-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIAQn88cSp7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-1994966112406252843</id><published>2011-02-06T13:47:00.000-05:00</published><updated>2011-11-11T15:49:03.179-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T15:49:03.179-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Information" /><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>A look in the past and the future [Update]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-3S214dx8LTA/Tr1uVH87WjI/AAAAAAAAFu0/21RSIwRGjjc/s1600/update.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="283" src="http://4.bp.blogspot.com/-3S214dx8LTA/Tr1uVH87WjI/AAAAAAAAFu0/21RSIwRGjjc/s320/update.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
It has been months since I last posted a blog post. A lot of things have happened since August and I have a lot of material to post - just not the discipline to sit down and proof all the drafts so that I can post them.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;2010
&lt;/b&gt;&lt;br /&gt;
2010 has been a rough year mostly on a personal level. I &lt;a href="http://www.niden.net/2010/05/update-personal.html"&gt;lost my brother in law&lt;/a&gt; in March, &lt;a href="http://www.niden.net/2010/05/update-personal.html"&gt;my daughter was born&lt;/a&gt; in May, there was great uncertainty at work during the summer, an upgrade went bad for Long Hair Care Forum to name a few of the highlights.&lt;br /&gt;
&lt;br /&gt;
Since this is officially my first year of blogging, I was happy to see some of the statistics for that year (well 8 months to be exact since I haven't posted since August).
&lt;br /&gt;
&lt;br /&gt;
&lt;table style="border: none;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="width: 140px;"&gt;Visits&lt;/td&gt;
&lt;td style="width: 140px;"&gt;8,940&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="width: 140px;"&gt;Pageviews&lt;/td&gt;
&lt;td style="width: 140px;"&gt;11,979&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="width: 140px;"&gt;Pages/Visit&lt;/td&gt;
&lt;td style="width: 140px;"&gt;1.41&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="width: 140px;"&gt;Bounce Rate&lt;/td&gt;
&lt;td style="width: 140px;"&gt;81.34%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="width: 140px;"&gt;Avg Time on Site&lt;/td&gt;
&lt;td style="width: 140px;"&gt;00:01:10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="width: 140px;"&gt;% New Visits&lt;/td&gt;
&lt;td style="width: 140px;"&gt;85.04%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="width: 140px;"&gt;&lt;/td&gt;
&lt;td style="width: 140px;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
The most visited posts were:
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.niden.net/2010/08/google-apps-and-google-accounts-merge.html"&gt;Google Apps and Google Accounts merge [Information][How-To]&lt;/a&gt; with&amp;nbsp;1,601 pageviews (13.37%)
&lt;a href="http://www.niden.net/2010/08/subversion-backup-how-to/"&gt;Subversion Backup [How-To]&lt;/a&gt; with&amp;nbsp;1,289 pageviews (10.76%)
&lt;a href="http://www.niden.net/2010/06/android-22-froyo-review.html"&gt; Android 2.2 (Froyo) [Review]&lt;/a&gt; with&amp;nbsp;1,124 pageviews (9.38%)
&lt;br /&gt;
&lt;br /&gt;
Not that bad for a first year.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;2011
&lt;/b&gt;&lt;br /&gt;
When I started blogging my main focus was to mostly address coding issues. However due to the plethora of solutions on the Internet, the content that I wanted to relay was not that interesting or had been covered a hundred times or more. For instance I did start posting about design patterns &lt;a href="http://www.niden.net/2010/01/design-patterns-singleton-serieshow-to.html"&gt;here&lt;/a&gt; and &lt;a href="http://www.niden.net/2010/02/design-patterns-factory-serieshow-to.html"&gt;here&lt;/a&gt;, but at the same time &lt;a href="http://giorgiosironi.blogspot.com/"&gt;Giorgio Sironi&lt;/a&gt; started blogging about design patterns and did an excellent job at it, so that topic was scrapped. My posts then started covering a much broader scope, mostly that of technology with a small personal flare.&lt;br /&gt;
&lt;br /&gt;
For 2011 I will continue on the same scope. I intend on blogging about interesting things technologically, how-to's and topics that I want to share with the community.
&lt;br /&gt;
&lt;br /&gt;
As always, whatever is presented in this blog is my personal opinion. Every post covered here as well with any code are free of copyright and you are free to use them in your projects at your own risk.
&lt;br /&gt;
&lt;br /&gt;
A big thank you to everyone that visited this blog whether you shared your opinion with me or not. I hope to meet the expectations of producing interesting content in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-1994966112406252843?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/yVsmfnuyob8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/1994966112406252843/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2011/02/look-in-past-and-future-update.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/1994966112406252843?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/1994966112406252843?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/yVsmfnuyob8/look-in-past-and-future-update.html" title="A look in the past and the future [Update]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-3S214dx8LTA/Tr1uVH87WjI/AAAAAAAAFu0/21RSIwRGjjc/s72-c/update.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2011/02/look-in-past-and-future-update.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEFR386fCp7ImA9WhRXFEw.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-9181400557699761009</id><published>2010-08-21T13:38:00.000-04:00</published><updated>2011-12-20T14:50:16.114-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-20T14:50:16.114-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Storage" /><category scheme="http://www.blogger.com/atom/ns#" term="Gentoo" /><category scheme="http://www.blogger.com/atom/ns#" term="Linux" /><category scheme="http://www.blogger.com/atom/ns#" term="Installation" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><category scheme="http://www.blogger.com/atom/ns#" term="Backup" /><title>Create an inexpensive hourly remote backup [How-To]</title><content type="html">&lt;blockquote&gt;
There are two kinds of people, those who backup regularly, and those that never had a hard drive fail&lt;/blockquote&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-u05g2O8FUvU/Tr1tS_Hv6LI/AAAAAAAAFuk/NblYWiD58Yw/s1600/remote_backup.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="251" src="http://1.bp.blogspot.com/-u05g2O8FUvU/Tr1tS_Hv6LI/AAAAAAAAFuk/NblYWiD58Yw/s320/remote_backup.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
As you can tell &lt;a href="http://www.niden.net/2010/08/subversion-backup-how-to/"&gt;the above is my favorite quote&lt;/a&gt;. It is so true and I believe everyone should evaluate how much their data (emails, documents, files) is worth to them and, based on that value, create a backup strategy that suits them. I know for sure that if I ever lost the pictures and videos of my family I would be devastated since those are irreplaceable.
&lt;br /&gt;
&lt;br /&gt;
So the question is how can I have an inexpensive backup solution? All my documents and emails are stored in Google, since my domain is on &lt;a href="http://www.google.com/a/"&gt;Google Apps&lt;/a&gt;. What happens to the live/development servers though that host all my work? I program on a daily basis and the code has to be backed up regularly so as to avoid any hard drive failures and thus result in loss of time and money.
&lt;br /&gt;
&lt;br /&gt;
So here is my solution. I have an old computer (IBM Thincentre) which I decided to beef up a bit. I bought 4Gb of RAM from eBay for less than $100 for it. Although this is was not necessary since my solution would be based on Linux (&lt;a href="http://www.gentoo.org/"&gt;Gentoo&lt;/a&gt; in particular), I wanted to have faster compilation times for packages.
&lt;br /&gt;
&lt;br /&gt;
I bought two external drives (750Gb and 500Gb respectively) and one 750Gb internal drive. I already have a 120Gb hard drive in the computer. The two external ones are connected to the computer using USB while the internal ones are connected using SATA.
&lt;br /&gt;
&lt;br /&gt;
The external drives are formatted using NTFS while the whole computer is built using ReiserFS.
&lt;br /&gt;
&lt;br /&gt;
Here is the approach:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;I have installed and have a working Gentoo installation on the machine&lt;/li&gt;
&lt;li&gt;I have an active Internet connection&lt;/li&gt;
&lt;li&gt;I have installed LVM on the machine and set up the core system on the 120Mb drive while the 500Mb is on LVM&lt;/li&gt;
&lt;li&gt;I have 300Mb active on the LVM (from the available 500Mb)&lt;/li&gt;
&lt;li&gt;I have generated a public SSH key (I will need this to exchange it with the target servers)&lt;/li&gt;
&lt;li&gt;I have mounted the internal 500Mb drive to the &lt;strong&gt;/storage&lt;/strong&gt; folder&lt;/li&gt;
&lt;li&gt;I have mounted the external USB 750Mb drive to the &lt;strong&gt;/backup_hourly&lt;/strong&gt; folder&lt;/li&gt;
&lt;li&gt;I have mounted the external USB 500Mb drive to the &lt;strong&gt;/backup_daily&lt;/strong&gt; folder&lt;/li&gt;
&lt;/ul&gt;
Here is how my backup works:
&lt;br /&gt;
&lt;br /&gt;
Every hour a script runs. The script uses rsync to syncrhonize files and folders from a remote server locally. Those files and folders are kept in relevant server named subfolders in the &lt;strong&gt;/storage&lt;/strong&gt; folder (remember this is my LVM). So for instance my subfolders will be &lt;strong&gt;/storage/beryllium.niden.net&lt;/strong&gt;, &lt;strong&gt;/storage/nitrogen.niden.net&lt;/strong&gt;, &lt;strong&gt;/storage/argon.niden.net&lt;/strong&gt; etc.
&lt;br /&gt;
&lt;br /&gt;
Once the rsync completes, the script continues by compressing the relevant 'server' folder and creates the compressed file with a date-time stamp on its name.
&lt;br /&gt;
&lt;br /&gt;
When all compressions are completed, if the time that the script has executed is midnight, the backups are moved from the &lt;strong&gt;/storage&lt;/strong&gt; folder to the &lt;strong&gt;/backup_daily&lt;/strong&gt; folder (which has the external USB 500Gb mounted). If it is any other time, the files are moved in the &lt;strong&gt;/backup_hourly&lt;/strong&gt; folder (which has the external USB 750Gb mounted).
&lt;br /&gt;
&lt;br /&gt;
This way I ensure that I keep a lot of backups (daily and hourly ones). The backups are being recycled, so older ones get deleted. The amount of data that you need to archive as well as the storage space you have available dictate how far back you can go in your hourly and daily cycles.
&lt;br /&gt;
&lt;br /&gt;
So let's get down to business. The script itself:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;#!/bin/bash
DATE=`date +%Y-%m-%d-%H-%M`
DATE2=`date +%Y-%m-%d`
DATEBACK_HOUR=`date --date='6 days ago' +%Y-%m-%d`
DATEBACK_DAY=`date --date='60 days ago' +%Y-%m-%d`
FLAGS="--archive --verbose --numeric-ids --delete --rsh='ssh'"
BACKUP_DRIVE="/storage"
DAY_USB_DRIVE="/backup_daily"
HOUR_USB_DRIVE="/backup_hourly"&lt;/pre&gt;
&lt;br /&gt;
These are some variables that I need for the script to work. The &lt;strong&gt;DATE&lt;/strong&gt; and &lt;strong&gt;DATE2&lt;/strong&gt; are used to date/time stamp the backups, while the &lt;strong&gt;DATEBACK_&lt;/strong&gt;* are used to clear previous backups. In this case it is set to 6 days ago (for my system). It can be set to whatever you want provided that you do not run out of space.
&lt;br /&gt;
&lt;br /&gt;
The &lt;strong&gt;FLAGS&lt;/strong&gt; variable keeps the rsync command options while the &lt;strong&gt;BACKUP_DRIVE&lt;/strong&gt;, &lt;strong&gt;DAY_USB_DRIVE&lt;/strong&gt; and &lt;strong&gt;HOUR_USB_DRIVE&lt;/strong&gt; hold the locations of the rsync folders, daily backup and hourly backup sorage areas.
&lt;br /&gt;
&lt;br /&gt;
The script works with arrays. I have 4 arrays to do the work and the 3 of them must have exactly the same elements.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;# RSync Information
rsync_info[1]="beryllium.niden.net html rsync"
rsync_info[2]="beryllium.niden.net db rsync"
rsync_info[3]="nitrogen.niden.net html rsync"
rsync_info[4]="nitrogen.niden.net html db"
rsync_info[5]="nitrogen.niden.net html svn"
rsync_info[6]="argon.niden.net html rsync"&lt;/pre&gt;
&lt;br /&gt;
This is the first array which holds descriptions to what needs to be done as far as source is concerned. These descriptions get appended to the log and helps me identify what step I am in.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;# RSync Source Folders
rsync_source[1]="beryllium.niden.net:/var/www/localhost/htdocs/"
rsync_source[2]="beryllium.niden.net:/niden_backup/db/"
rsync_source[3]="nitrogen.niden.net:/var/www/localhost/htdocs/"
rsync_source[4]="nitrogen.niden.net:/niden_backup/db"
rsync_source[5]="nitrogen.niden.net:/niden_backup/svn"
rsync_source[6]="argon.niden.net:/var/www/localhost/htdocs/"&lt;/pre&gt;
&lt;br /&gt;
This array holds the source host and folder. Remember that I have already exchanged SSH keys with each server, therefore when the script runs there is a direct connection to the source server. If you need to keep things a bit more secure for you, then you will need to alter the contents of the rsync_source array so that it reflects the user that you log in with as well as the password.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;# RSync Target Folders
rsync_target[1]="beryllium.niden.net/html/"
rsync_target[2]="beryllium.niden.net/db/"
rsync_target[3]="nitrogen.niden.net/html/"
rsync_target[4]="nitrogen.niden.net/db/"
rsync_target[5]="nitrogen.niden.net/svn/"
rsync_target[6]="argon.niden.net/html/"&lt;/pre&gt;
&lt;br /&gt;
This array holds the target locations for the rsync. These folders exist in my case under the &lt;strong&gt;/storage&lt;/strong&gt; subfolder.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;# GZip target files
servers[1]="beryllium.niden.net"
servers[2]="nitrogen.niden.net"
servers[3]="argon.niden.net"&lt;/pre&gt;
&lt;br /&gt;
This array holds the names of the folders to be archived. These are the folders directly under the &lt;strong&gt;/storage&lt;/strong&gt; folder and I am also using this array for the prefix of the compressed files. The suffix of the compressed files is a date/time stamp.
&lt;br /&gt;
&lt;br /&gt;
Here is how the script evolves:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;echo "BACKUP START"  &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
date &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log

echo "BACKUP START" &amp;nbsp;&amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
date &amp;nbsp;&amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log

# Loop through the RSync process
element_count=${#rsync_info[@]}
let "element_count = $element_count + 1"
index=1
while [ "$index" -lt "$element_count" ]
do
    echo ${rsync_info[$index]} &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    rsync $FLAGS ${rsync_source[$index]} $BACKUP_DRIVE/${rsync_target[$index]} &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    let "index = $index + 1"
done&lt;/pre&gt;
&lt;br /&gt;
The snippet above loops through the &lt;strong&gt;rsync_info&lt;/strong&gt; array and prints out the information in the log file. Right after that it uses the &lt;strong&gt;rsync_source&lt;/strong&gt; and &lt;strong&gt;rsync_target&lt;/strong&gt; arrays (as well as the &lt;strong&gt;FLAGS&lt;/strong&gt; variable) to rsync the contents of the source server with the local folder. Remember that all three arrays have to be identical in size (&lt;strong&gt;rsync_info&lt;/strong&gt;, &lt;strong&gt;rsync_source&lt;/strong&gt;, &lt;strong&gt;rsync_target&lt;/strong&gt;).
&lt;br /&gt;
&lt;br /&gt;
The next thing to do is zip the data (I loop through the servers array)
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;# Looping to GZip data
element_count=${#servers[@]}
let "element_count = $element_count + 1"
index=1
while [ "$index" -lt "$element_count" ]
do
    echo "GZip ${servers[$index]}" &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    tar cvfz $BACKUP_DRIVE/${servers[$index]}-$DATE.tgz $BACKUP_DRIVE/${servers[$index]} &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    let "index = $index + 1"
done&lt;/pre&gt;
&lt;br /&gt;
The compression method I use is tar/gzip. I found it to be fast with a good compression ratio. You can choose anything you like.
&lt;br /&gt;
&lt;br /&gt;
Now I need to delete old files from the drives and copy the files on those drives. I use the servers array again.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;# Looping to copy the produced files (if applicable) to the daily drive
element_count=${#servers[@]}
let "element_count = $element_count + 1"
index=1

while [ "$index" -lt "$element_count" ]
do
    # Copy the midnight files
    echo "Removing old daily midnight files" &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    rm -f $DAY_USB_DRIVE/${servers[$index]}/${servers[$index]}-$DATEBACK_DAY*.* &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    echo "Copying daily midnight files" &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
 &amp;nbsp; &amp;nbsp;cp -v $BACKUP_DRIVE/${servers[$index]}-$DATE2-00-*.tgz $DAY_USB_DRIVE/${servers[$index]} &amp;nbsp;&amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
 &amp;nbsp; &amp;nbsp;rm -f $BACKUP_DRIVE/${servers[$index]}-$DATE2-00-*.tgz &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log

    # Now copy the files in the hourly
    echo "Removing old hourly files" &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    rm -f $HOUR_USB_DRIVE/${servers[$index]}/${servers[$index]}-$DATEBACK_HOUR*.* &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    echo "Copying daily midnight files" &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    cp -v $BACKUP_DRIVE/${servers[$index]}-$DATE.tgz $HOUR_USB_DRIVE/${servers[$index]} &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
    rm -f $HOUR_USB_DRIVE/${servers[$index]}/${servers[$index]}-$DATEBACK*.* &amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log
 &amp;nbsp; &amp;nbsp;let "index = $index + 1"
done

echo "BACKUP END" &amp;nbsp;&amp;gt;&amp;gt; $BACKUP_DRIVE/logs/$DATE.log&lt;/pre&gt;
&lt;br /&gt;
The last part of the script loops through the servers array and:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Deletes the old files (recycling of space) from the daily backup drive (&lt;strong&gt;/storage/backup_daily&lt;/strong&gt;) according to the &lt;strong&gt;DATEBACK_DAY&lt;/strong&gt; variable. If the files are not found a warning will appear in the log.&lt;/li&gt;
&lt;li&gt;Copies the daily midnight file to the daily drive (if the file does not exist it will simply echo a warning in the log - I do not worry about warnings of this kind in the log file and was too lazy to use an IF EXISTS condition)&lt;/li&gt;
&lt;li&gt;Removes the daily midnight file from the &lt;strong&gt;/storage&lt;/strong&gt; drive.&lt;/li&gt;
&lt;/ol&gt;
The reason I am using copy and then remove instead of the move (&lt;strong&gt;mv&lt;/strong&gt;) command is that I have found this method to be faster.

Finally the same thing happens with the hourly files
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Old files are removed (&lt;strong&gt;DATEBACK_HOUR&lt;/strong&gt; variable)&lt;/li&gt;
&lt;li&gt;Hourly file gets copied to the &lt;strong&gt;/backup_hourly&lt;/strong&gt; drive&lt;/li&gt;
&lt;li&gt;Hourly file gets deleted from the &lt;strong&gt;/storage&lt;/strong&gt; drive&lt;/li&gt;
&lt;/ol&gt;
All I need now is to add the script in my crontab and let it run every hour.

&lt;strong&gt;NOTE&lt;/strong&gt;: The first time you will run the script you will need to do it manually (not in a cron job). The reason behind it is that the first time rsync will need to download all the contents of the source servers/folders in the &lt;strong&gt;/storage&lt;/strong&gt; drive so as to create an exact mirror. Once that lengthy step is done, the script can be added in the crontab. Subsequent runs of the script will download only the changed/deleted files.
&lt;br /&gt;
&lt;br /&gt;
This method can be very effective while not using a ton of bandwidth every hour. I have used this method for the best part of a year now and it has saved me a couple of times.
&lt;br /&gt;
&lt;br /&gt;
The last thing I need to present you is the backup script that I have for my databases. As you notice above the source folder of beryllium.niden.net as far as databases are concerned is &lt;strong&gt;beryllium.niden.net/db/&lt;/strong&gt;. What I do is I dump and zip the databases every hour on my servers. Although this is not a very efficient way of doing things and it adds to the bandwidth consumption every hour (since the dump will create a new file every hour) I have the following script running on my database servers every hour at the 45th minute:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;#!/bin/bash

DBUSER=mydbuser
DBPASS='dbpassword'
DBHOST=localhost
BACKUPFOLDER="/niden_backup"
DBNAMES="`mysql --user=$DBUSER --password=$DBPASS --host=$DBHOST --batch --skip-column-names -e "show databases"| sed 's/ /%/g'`"
OPTIONS="--quote-names --opt --compress "

# Clear the backu folder
rm -fR $BACKUPFOLDER/db/*.*

for i in $DBNAMES; do
    echo Dumping Database: $i
    mysqldump --user=$DBUSER --password=$DBPASS --host=$DBHOST $OPTIONS $i &amp;gt; $BACKUPFOLDER/db/$i.sql
    tar cvfz $BACKUPFOLDER/db/$i.tqz $BACKUPFOLDER/db/$i.sql
    rm -f $BACKUPFOLDER/db/$i.sql
done&lt;/pre&gt;
&lt;br /&gt;
That's it.
&lt;br /&gt;
&lt;br /&gt;
The backup script can be found in my GitHub&amp;nbsp;&lt;a href="https://github.com/niden/Hourly_Backup_Linux"&gt;here&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
Update: The metric units for the drives were GB not MB. Thanks to &lt;a href="http://www.codeutopia.net/"&gt;Jani Hartikainen&lt;/a&gt; for pointing it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-9181400557699761009?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/1MzZRSLNZV0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/9181400557699761009/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/08/create-inexpensive-hourly-remote-backup.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/9181400557699761009?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/9181400557699761009?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/1MzZRSLNZV0/create-inexpensive-hourly-remote-backup.html" title="Create an inexpensive hourly remote backup [How-To]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-u05g2O8FUvU/Tr1tS_Hv6LI/AAAAAAAAFuk/NblYWiD58Yw/s72-c/remote_backup.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/08/create-inexpensive-hourly-remote-backup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08DRHk8eyp7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-2431998592010948917</id><published>2010-08-18T13:17:00.000-04:00</published><updated>2011-11-11T16:11:15.773-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T16:11:15.773-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Information" /><category scheme="http://www.blogger.com/atom/ns#" term="Google" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Apps" /><title>Google Apps and Google Accounts merge [Information][How-To]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-mTZTSrlAoVU/Tr1yc7fWhlI/AAAAAAAAFvs/-Xf-jfj6KfY/s1600/google-apps-logo-150x150.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-mTZTSrlAoVU/Tr1yc7fWhlI/AAAAAAAAFvs/-Xf-jfj6KfY/s1600/google-apps-logo-150x150.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
Anyone that has a Google Apps account and wants to access other services like &lt;a href="http://reader.google.com/"&gt;Google Reader&lt;/a&gt;, &lt;a href="http://voice.google.com/"&gt;Google Voice&lt;/a&gt; etc. knows that the username and password of the Google Apps account does not work for these services, since&amp;nbsp;those are not available for Google Apps accounts. To get around this limitation, what you could do (and what I have done in the past) is to sign up for a new Google Account with the same email address as your Google Apps account. &amp;nbsp;This of course creates confusion at times, duplication of data and&amp;nbsp;disassociation&amp;nbsp;of services. The most obvious example of this is on an Android device. To use my phone, I need to sign in with my Google Apps account. However, to use my Google Voice number, I &amp;nbsp;have to use sign in again for that service but now using my Google Account (which uses the same email address). This works but I still have to keep two sets of contacts - one for the Google Apps and one in Google Voice.
&lt;br /&gt;
&lt;br /&gt;
According to Google, &lt;a href="http://productideas.appspot.com/#25/e=2199b"&gt;9 of the top 20 requests&lt;/a&gt; from Google Apps customers are for their accounts to work with more services from Google. To facilitate this, the Google Apps account had to be merged with the Google Account. This page in Google Apps Help that&amp;nbsp;&lt;a href="http://www.google.com/support/accounts/bin/answer.py?hl=en&amp;amp;answer=182174"&gt;describes&lt;/a&gt; the transition.
&lt;br /&gt;
&lt;br /&gt;
Unfortunately this was not a simple flip of a switch for Google. &lt;a href="http://googleenterprise.blogspot.com/2010/05/more-google-applications-coming-for.html"&gt;Significant infrastructure changes&lt;/a&gt; had to be in place prior to the merging of the accounts. We were promised that this change would be in place by fall and we have not been disappointed. Google is rolling out the update slowly but if you want to 'speed up' the process, you can &lt;a href="https://spreadsheets1.google.com/a/google.com/viewform?hl=en&amp;amp;formkey=dGdfTTA2eGhFT0c0SDVLXzMzMFNwUUE6MA#gid=0"&gt;sign up&lt;/a&gt; for an early round of testing of the new infrastructure. I have signed up for several of my Google Apps domains a couple of weeks ago.
&lt;br /&gt;
&lt;br /&gt;
I am happy to announce that one of my domains has already gone through the merge process. The domain is&amp;nbsp;&lt;a href="http://wwww.beautyandthegeek.it/"&gt;BeautyAndTheGeek.IT&lt;/a&gt; which is a Google Apps Premier edition. My other domains that are hosted in Google Apps have not transitioned yet and I suspect that Google is first merging Premium accounts, then Educational, Government and it will finish up with the Standard edition of Google Apps, which kind of makes sense (paid customers first!).
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Email Invitation
&lt;/b&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-eQuK_0CsPMo/Tr1oAlGyzCI/AAAAAAAAFuE/p-UJPJEpIUA/s1600/8-Google-Apps-Initial-Email.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="305" src="http://3.bp.blogspot.com/-eQuK_0CsPMo/Tr1oAlGyzCI/AAAAAAAAFuE/p-UJPJEpIUA/s320/8-Google-Apps-Initial-Email.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Invitation email to the Admin&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
The day before yesterday I received an email inviting me to participate in the new infrastructure change and merge the Google Apps accounts with the Google Accounts of my users.&lt;br /&gt;
&lt;br /&gt;
The merge process works as follows:
&lt;br /&gt;
&lt;br /&gt;
- If your Google Apps account email address &lt;strong&gt;&lt;span style="text-decoration: underline;"&gt;has never been used&lt;/span&gt;&lt;/strong&gt; to access Google products such as Google Reader, Google Voice, Google Code etc. then your Google Apps account will be converted to a Google Account.
&lt;br /&gt;
&lt;br /&gt;
- If your Google Apps account email address &lt;strong&gt;&lt;span style="text-decoration: underline;"&gt;has been used&lt;/span&gt;&lt;/strong&gt; to access Google products such as Google Reader, Google Voice, Google Code etc. then your Google Apps account is conflicting with your Google Account. This&amp;nbsp;&lt;a href="http://www.google.com/support/a/bin/answer.py?answer=184937"&gt;page&lt;/a&gt; in Google Apps Administrator Help provides an overview of conflicting accounts. In short both of your accounts will merge and the data will be associated with your Google Apps account, which will now be the same as your Google Account.
&lt;br /&gt;
&lt;br /&gt;
There are certain limitations to this merge (as one would expect :)). These are as follows:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;If the offline feature is enabled in GMail, the user has to synchronize before the transition. If they don't, they will lose their offline messages.&lt;/li&gt;
&lt;li&gt;Offline Google Calendar doesn't work for Google Apps accounts that have transitioned.&lt;/li&gt;
&lt;li&gt;The following Google products don't work with Google Apps accounts that have transitioned:
&lt;ul&gt;
&lt;li&gt;Android Market for Developers&lt;/li&gt;
&lt;li&gt;Google Extra Storage (bummer)&lt;/li&gt;
&lt;li&gt;Health (bummer again)&lt;/li&gt;
&lt;li&gt;PowerMeter&lt;/li&gt;
&lt;li&gt;Profiles&lt;/li&gt;
&lt;li&gt;Web History&lt;/li&gt;
&lt;li&gt;YouTube&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The purchase of additional Google Storage is currently unavailable for Google Apps accounts. No storage can be purchased for a Google Apps account, although it will be available later this year. If a user account has already purchased extra storage (like I have) in an existing Google Account, the storage will remain in that account and will not transfer to the respective Google Apps account after the transition.&lt;/li&gt;
&lt;li&gt;Delegating email only works with the same account type (i.e. Google Apps)&lt;/li&gt;
&lt;li&gt;Any Picasa Web Album, Profile, or Wave usernames cannot be moved from an existing account to your Google Apps account.&lt;/li&gt;
&lt;/ol&gt;
Resources:&amp;nbsp;&lt;a href="http://www.google.com/support/a/bin/answer.py?answer=182034"&gt;Transition readiness checklist&lt;/a&gt;, &lt;a href="http://www.google.com/support/a/bin/answer.py?answer=184937"&gt;Conflicting accounts&lt;/a&gt;, &lt;a href="http://www.google.com/support/a/bin/answer.py?answer=181872"&gt;Early adopters&lt;/a&gt;,&amp;nbsp;&lt;a href="http://www.google.com/support/a/bin/answer.py?answer=172732"&gt;Additional storage for Google Apps&lt;/a&gt;, &lt;a href="http://www.google.com/support/a/bin/topic.py?topic=28917"&gt;Google Apps Administrator Help Center&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The process
&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Google Apps - Dashboard Warning&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-JXAri_5DQKQ/Tr1oq2HKljI/AAAAAAAAFuU/Ohs7V1I6Oos/s1600/0-Google-Apps-Warning.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="67" src="http://3.bp.blogspot.com/-JXAri_5DQKQ/Tr1oq2HKljI/AAAAAAAAFuU/Ohs7V1I6Oos/s320/0-Google-Apps-Warning.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Dashboard Warning&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Once I logged in my Google Apps Administration area, the Dashboard presented a new notice at the top. In short the notice states that new services will be available to the Google Apps accounts. This will be achieved with the transition of the Google Apps Account to a Google Account. The update is free and Google will automatically roll it out on &lt;strong&gt;September 30, 2010&lt;/strong&gt;.&lt;br /&gt;
&lt;br /&gt;
Resource: &lt;a href="http://www.google.com/apps/intl/en/business/index.html"&gt;Google Apps core suite&lt;/a&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Google Apps - Understand Transition&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-yZUCAtPAb58/Tr1n-lLKmPI/AAAAAAAAFtM/uGIRZd6D4As/s1600/1-Google-Apps-Understand-Transition.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="102" src="http://4.bp.blogspot.com/-yZUCAtPAb58/Tr1n-lLKmPI/AAAAAAAAFtM/uGIRZd6D4As/s320/1-Google-Apps-Understand-Transition.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Understanding the transition&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Clicking the "&lt;strong&gt;Get Started&lt;/strong&gt;" button at the bottom of the notice will start a wizard that helps with the transition of the domain's accounts to Google accounts of your users (some or all). The first screen contains information that aids in understanding the transition and what is involved. &amp;nbsp; Moving to the new infrastructure will update your control panel and give you control over which Google services your users can access with their accounts.&lt;br /&gt;
&lt;br /&gt;
Resource: &lt;a href="http://www.google.com/support/a/bin/answer.py?answer=182034"&gt;Transition readiness checklist&lt;/a&gt;,&amp;nbsp;&lt;a href="http://www.google.com/support/a/bin/topic.py?topic=28917"&gt;Google Apps Administrator Help Center&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Google Apps - New Services&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-t7-9HjpiQHA/Tr1n-1egzwI/AAAAAAAAFtU/p6cCsrKS4Y4/s1600/2-Google-Apps-Review-New-Services.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="134" src="http://1.bp.blogspot.com/-t7-9HjpiQHA/Tr1n-1egzwI/AAAAAAAAFtU/p6cCsrKS4Y4/s320/2-Google-Apps-Review-New-Services.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Review New Services&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Based on the services that are available for your domain user accounts, the screen above might be slightly different. It does however give you (the administrator) the ability to enable or disable services for your users. Note that turning off a service will disallow your users to sign up for that service using their Google Apps account for your domain. It will however not stop them from using a totally different Google Account (personal for instance) to access that service.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Google Apps - Notify Conflicting Accounts&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-TeXdiNbjvBw/Tr1n_ZGBRZI/AAAAAAAAFtc/toBdGEdrBK4/s1600/3-Google-Apps-Notify-Conflicting-Accounts.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="99" src="http://2.bp.blogspot.com/-TeXdiNbjvBw/Tr1n_ZGBRZI/AAAAAAAAFtc/toBdGEdrBK4/s320/3-Google-Apps-Notify-Conflicting-Accounts.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Notify Conflicting Accounts&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Confirming the new services, the wizard will display a new screen, that will allow you to notify those users that have conflicting accounts. This screen provides information on how many users have conflicting accounts (in my case only 1), what happens to those accounts (the merge process) and what should you do as the administrator. Google will not provide information on which of your users have conflicting accounts. What they will however do, is offer you a temporary email address and an email template, that you can use to email your users. The email template is shown in the "&lt;em&gt;Google Apps - Email to User&lt;/em&gt;"&amp;nbsp;section below.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Google Apps - Select Users&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-eDp78iqlgZk/Tr1n_gCrheI/AAAAAAAAFtk/4GVaq38K4LM/s1600/4-Google-Apps-Select-Users.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="92" src="http://3.bp.blogspot.com/-eDp78iqlgZk/Tr1n_gCrheI/AAAAAAAAFtk/4GVaq38K4LM/s320/4-Google-Apps-Select-Users.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Select Users&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Clicking "&lt;strong&gt;Continue&lt;/strong&gt;", brings up the User Selection screen. Here the administrator can select whose account will be transitioned for now. You can choose to pilot test this transition with a small set of users or everyone. The difference is that if you choose a small set of users to pilot test this transition, you can revert their accounts back to what they were prior to this step. If you choose "&lt;em&gt;Everyone&lt;/em&gt;" from this screen, the change will be across the organization and cannot be undone. Reminder here that the transition will happen either way by the end of September, 2010. Finally you have the option to inform the users when their account transition is complete. This generates an email (in English) to the user with relevant information. You can see the email in section "&lt;em&gt;Google Apps - Email to User&lt;/em&gt;" below.&lt;br /&gt;
&lt;br /&gt;
Resource: &lt;a href="http://www.google.com/support/a/bin/answer.py?answer=181872"&gt;Early adopters&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Google Apps - Confirmation&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-3OXb8vEHTZ8/Tr1n_3pyJ3I/AAAAAAAAFts/uKNEeU60ANI/s1600/5-Google-Apps-Confirm.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="156" src="http://3.bp.blogspot.com/-3OXb8vEHTZ8/Tr1n_3pyJ3I/AAAAAAAAFts/uKNEeU60ANI/s320/5-Google-Apps-Confirm.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Confirmation&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Clicking "&lt;strong&gt;Continue&lt;/strong&gt;"again will bring up the final screen which is the confirmation page. Google is very thorough and I like the confirmation screen. The information in this screen is a summary of what the wizard collected in previous steps. You (the administrator) will have to confirm in several places that you have understood the process, read the agreement and then accept the whole process. Clicking "&lt;strong&gt;I accept. Start the transition.&lt;/strong&gt;" will make things happen :)&lt;br /&gt;
&lt;br /&gt;
Resources: &lt;a href="http://www.google.com/support/a/bin/answer.py?answer=182034"&gt;Transition readiness checklist&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;i&gt;Google Apps - Transition in progress&lt;/i&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-tTcM-E4r6VQ/Tr1p_OKYkSI/AAAAAAAAFuc/PKNxe3YxI00/s1600/6-Google-Apps-Transition-In-Progress.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="27" src="http://3.bp.blogspot.com/-tTcM-E4r6VQ/Tr1p_OKYkSI/AAAAAAAAFuc/PKNxe3YxI00/s320/6-Google-Apps-Transition-In-Progress.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Transition in Progress&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Navigating back to the dashboard, you will see a message notifying you that there is a transition in place for the accounts of your domain and can take up to 24 hours to be completed. This serves as a reminder on what has just happened. The notice will disappear once the transition is completed.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Google Apps - Email to User&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-PDLt5BB8C4Q/Tr1oAJHFcrI/AAAAAAAAFt0/OaMslUMWQEQ/s1600/7-Google-Apps-Email-To-User.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="221" src="http://4.bp.blogspot.com/-PDLt5BB8C4Q/Tr1oAJHFcrI/AAAAAAAAFt0/OaMslUMWQEQ/s320/7-Google-Apps-Email-To-User.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Email to User&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
If you (the administrator) chose to notify your users of this transition (see step &lt;em&gt;Select Users&lt;/em&gt; above), they will receive an email like the one shown above. If you chose to notify your users with a different message then that message should have been sent to the temporary email address that Google has provided (see step &lt;em&gt;Notifying Conflicting Accounts&lt;/em&gt; above)&lt;br /&gt;
&lt;br /&gt;
Resources: &lt;a href="http://www.google.com/support/accounts/bin/answer.py?answer=181692"&gt;Data ownership&lt;/a&gt;,&amp;nbsp;&lt;a href="http://www.google.com/support/a/bin/answer.py?answer=182034"&gt;Transition readiness checklist&lt;/a&gt;,&amp;nbsp;&lt;a href="http://www.google.com/support/a/bin/topic.py?topic=28917"&gt;Google Apps Administrator Help Center&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Google Apps -&amp;nbsp;Email to User after Transition&lt;/i&gt;&lt;/b&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-8mqZ84yRvpg/Tr1oAaRbGUI/AAAAAAAAFt8/8G9gPXaLb4Y/s1600/7-Google-Apps-Email-To-User-After.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="297" src="http://2.bp.blogspot.com/-8mqZ84yRvpg/Tr1oAaRbGUI/AAAAAAAAFt8/8G9gPXaLb4Y/s320/7-Google-Apps-Email-To-User-After.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Email to User after transition&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Finally another email will be sent to the user summarizing what has happened with their account. This email contains links to additional resources.&lt;br /&gt;
&lt;br /&gt;
Resources: &lt;a href="http://www.google.com/options/"&gt;List of products&lt;/a&gt;, &lt;a href="http://www.google.com/support/accounts/bin/answer.py?answer=181703"&gt;New sign in option&lt;/a&gt;, &amp;nbsp;&lt;a href="http://www.google.com/support/accounts/bin/answer.py?answer=181692"&gt;Data ownership&lt;/a&gt;, &lt;a href="http://www.whatbrowser.org/en/"&gt;What is a browser?&lt;/a&gt;, &lt;a href="http://www.google.com/support/accounts/bin/answer.py?hl=en&amp;amp;answer=182343"&gt;Using multiple accounts&lt;/a&gt;, &lt;a href="http://www.google.com/support/a/bin/topic.py?topic=28917"&gt;Help Center for Admins&lt;/a&gt;, &lt;a href="http://www.google.com/support/a/bin/topic.py?topic=28917"&gt;Google Apps Administrator Help Center&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Google Apps -&amp;nbsp;User Login message for Account Merge&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;/div&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-SL3793sD_bQ/Tr1oAxeKJHI/AAAAAAAAFuM/4fGs6KuEkBc/s1600/9-Google-Apps-User-Perspective.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="122" src="http://1.bp.blogspot.com/-SL3793sD_bQ/Tr1oAxeKJHI/AAAAAAAAFuM/4fGs6KuEkBc/s320/9-Google-Apps-User-Perspective.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Message to user after login for account merge&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Once the transition operation is completed, the next time the user logs in their account, they will see the screen above. In short this screen informs the user of what has happened and provides links to online resources for help. The user must click "&lt;strong&gt;I accept. Continue to my account.&lt;/strong&gt;" for them to have access to their account. This is &amp;nbsp;a one off process.
&lt;br /&gt;
&lt;br /&gt;
Resources: &lt;a href="http://www.google.com/support/a/bin/topic.py?topic=28917"&gt;Google Apps Administrator Help Center&lt;/a&gt;, &lt;a href="http://www.google.com/support/a/bin/answer.py?hl=en&amp;amp;answer=60762"&gt;Google Security and Privacy&lt;/a&gt;, &lt;a href="http://www.google.com/support/accounts/bin/answer.py?hl=en&amp;amp;answer=182343"&gt;Using multiple accounts&lt;/a&gt;, &lt;a href="http://www.google.com/apps/intl/en/terms/user_terms.html"&gt;Terms of Service&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;
Without a doubt this is a huge step forward for Google and for us as admins or users. The ability to have a single sign on to use their products not only helps them but us by simplifying everything. That also means that if a hacker guesses that my password is "&lt;strong&gt;password1&lt;/strong&gt;" they have access to all my Google related services... but oh well :)&lt;br /&gt;
&lt;br /&gt;
Joking apart though, I am really excited that this change has finally occurred. I am guessing that the next steps would be to give users or admins the ability&amp;nbsp;to purchase additional storage for a single account is something that in my view will make quite a lot of money for Google. A lot of people will want to keep all their emails and are nearing or have reached their email quota. Administrators would be happy to pay for certain users that have&amp;nbsp;depleted their email storage allocation without converting their whole Google Apps edition to the Premier one. After all, if your organization has 100 users and 5 of them are near capacity, even if you pay $20 per user it will cost $100 per year. If however the whole account is changed to a Premier account (with 25Gb per mailbox) the cost will go up to $5,000.
&lt;br /&gt;
&lt;br /&gt;
Some questions come to mind:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Will the user be able to purchase storage for all services or just for email?&lt;/li&gt;
&lt;li&gt;Will the 1Gb limit from Docs be lifted and will it be combined with storage for mail?&lt;/li&gt;
&lt;li&gt;$20 a year gives you 80Gb in Picasa. Will Google follow that model or change it? According to the &lt;a href="http://www.google.com/support/a/bin/answer.py?answer=172732"&gt;Additional storage for Google Apps&lt;/a&gt; page it appears that it will be more expensive now to have more space.&lt;/li&gt;
&lt;li&gt;If storage is so cheap (Picasa) will it be extended to Google Documents? It appears that 7.5Gb is enough for the vast majority of users as far as email is concerned, but 1Gb for Docs is not enough. For a society moving towards a full electronic document storage this could help a lot.&lt;/li&gt;
&lt;/ol&gt;
Still a long way to go until everything clears up. I am not sure that Google has all the answers yet but they are moving forward and this is the most encouraging news of all!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-2431998592010948917?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/3I1ZsS0ACDI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/2431998592010948917/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/08/google-apps-and-google-accounts-merge.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/2431998592010948917?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/2431998592010948917?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/3I1ZsS0ACDI/google-apps-and-google-accounts-merge.html" title="Google Apps and Google Accounts merge [Information][How-To]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-mTZTSrlAoVU/Tr1yc7fWhlI/AAAAAAAAFvs/-Xf-jfj6KfY/s72-c/google-apps-logo-150x150.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/08/google-apps-and-google-accounts-merge.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QDQnk-fCp7ImA9WhRSEE4.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-1642939403445780163</id><published>2010-08-01T13:11:00.000-04:00</published><updated>2011-11-11T13:16:13.754-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T13:16:13.754-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Gentoo" /><category scheme="http://www.blogger.com/atom/ns#" term="Subversion" /><category scheme="http://www.blogger.com/atom/ns#" term="Linux" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><category scheme="http://www.blogger.com/atom/ns#" term="Backup" /><title>Subversion Backup [How-To]</title><content type="html">I will start this post once again with the words of a wise man:
&lt;br /&gt;
&lt;blockquote&gt;
There are two kinds of people, those who backup regularly, and those that never had a hard drive fail&lt;/blockquote&gt;
So the moral of the story here is &lt;strong&gt;backup often&lt;/strong&gt;. If something is to happen, the impact on your operations will be minimal if your backup strategy is in place and operational.
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-NmcW5e17XbE/Tr1mJtrS3mI/AAAAAAAAFtE/pfdFLYyrku4/s1600/online-backup.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="212" src="http://1.bp.blogspot.com/-NmcW5e17XbE/Tr1mJtrS3mI/AAAAAAAAFtE/pfdFLYyrku4/s320/online-backup.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
There are a lot of backup scenarios and strategies. Most of them suggest a backup once a day, usually at the early hours of the day. This however might not work very well with a fast paced environment where data changes several times per hour. This kind of environment is usually a software development one.
&lt;br /&gt;
&lt;br /&gt;
If you have chosen &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; to be your software version control software then you will need a backup strategy for your repositories. Since the code changes very often, this strategy cannot rely on the daily backup schedule. The reason being is that, in software, a day's worth of work usually costs a lot more than the actual daily rate of the programmers.
&lt;br /&gt;
&lt;br /&gt;
Below are some of the scripts I have used over the years for my incremental backups, that I hope will help you too. You are more than welcome to copy and paste the scripts and use them &amp;nbsp;or modify them to suit your needs. Please note though that the scripts are provided as is and that you must check your backup strategy with a full backup/restore cycle. I cannot assume responsibility of something that might happen in your system.
&lt;br /&gt;
&lt;br /&gt;
Now that the 'legal' stuff are out of the way, here are the different strategies that you can adopt. :)
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;svn-hot-backup
&lt;/b&gt;&lt;br /&gt;
This is a script that is provided with &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;. It copies (and compresses if requested) the whole repository to a specified location. This technique allows for a full copy of the repository to be moved to a different location. The target location can be a resource on the local machine or a network resource. You can also backup on the local drive and then as a next step transfer the target files to an offsite location with &lt;a href="http://en.wikipedia.org/wiki/File_Transfer_Protocol"&gt;FTP&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Secure_copy"&gt;SCP&lt;/a&gt;, &lt;a href="http://www.samba.org/rsync/"&gt;RSync&lt;/a&gt; or any other mechanism you prefer.&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;#!/bin/bash

# Grab listing of repositories and copy each
# repository accordingly

SVNFLD="/var/svn"
BACKUPFLD="/backup"

# First clean up the backup folder
rm -f $BACKUPFLD/*.*

for i in $(ls -1v $SVNFLD); do
    if [ $i != 'conf' ]; then
        /usr/bin/svn-hot-backup --archive-type=bz2 $SVNFLD/$i $BACKUPFLD
    fi
done&lt;/pre&gt;
&lt;br /&gt;
This script will create a copy of each of your repositories and compress it as a bz2 file in the target location. Note that I am filtering for 'conf'. The reason being is that I have a conf file with some configuration scripts in the same SVN folder. You can adapt the script to your needs to include/exclude repositories/folders as needed.
&lt;br /&gt;
&lt;br /&gt;
This technique gives the ability to immediately restore a repository (or more than one) by changing the configuration file of SVN to point to the backup location. If you run the script every hour or so then your downtime and loss will be minimal, should something happens.
&lt;br /&gt;
&lt;br /&gt;
There are some configuration options that you can tweak by editing the actual svn-hot-backup script. In Gentoo it is located under &lt;em&gt;/usr/bin/&lt;/em&gt;. The default number of backups (&lt;em&gt;num_backups&lt;/em&gt;) that the script will keep is 64. You can choose 0 to 'keep them all' but you can adjust it according to your storage or your backup strategy.
&lt;br /&gt;
&lt;br /&gt;
One last thing to note is that you can change the compression mechanism by changing the parameter of the &lt;em&gt;--archive-type&lt;/em&gt; option. The compression types supported are gz (.tar.gz), bz2 (.tar.bz2) and zip (.zip)
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Full backup using dump
&lt;/b&gt;&lt;br /&gt;
This method is similar to the svn-hot-backup. It works by 'dumping' the repository in a portable file format and compressing it.&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;#!/bin/bash

# Grab listing of folders and dump each
# repository accordingly

SVNFLD="/var/svn"
BACKUPFLD="/backup"

# First clean up the backup folder
rm -f $BACKUPFLD/svn/*.*

for i in $(ls -1v $SVNFLD); do
    if [ $i != 'conf' ]; then
        svnadmin dump $SVNFLD/$i/ &amp;gt; $BACKUPFLD/$i.svn.dump
        tar cvfz $BACKUPFLD/svn/$i.tgz $BACKUPFLD/$i.svn.dump
        rm -f $BACKUPFLD/$i.svn.dump
    fi
done&lt;/pre&gt;
&lt;br /&gt;
As you can see, this version does the same thing as the &lt;em&gt;svn-hot-backup&lt;/em&gt;. It does however give you a bit more control over the whole backup process and allows for a different compression mechanism - since the compression happens on a separate line in the script.
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;NOTE:&lt;/strong&gt; If you use the &lt;em&gt;hotcopy&lt;/em&gt; parameter in &lt;em&gt;svnadmin&lt;/em&gt; (&lt;em&gt;svnadmin hotcopy .....&lt;/em&gt;) you will effectively be duplicating the behavior of &lt;em&gt;svn-hot-backup&lt;/em&gt;.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Incremental backup using dump based on revision
&lt;/b&gt;&lt;br /&gt;
This last method is what I use at work. We have our repositories backed up externally and we rely on the backup script to have everything backed up and transferred to the external location within an hour, since our backup strategy is an hourly backup. We have discovered that sometimes the size of a repository can cause problems with the transfer, since the Internet line will not be able to transfer the files across in the allocated time. This happened once in the past with a repository that ended up being 500Mb (don't ask :)).&lt;br /&gt;
&lt;br /&gt;
So in order to minimize the upload time, I have altered the script to dump each repository's revision in a separate file. Here is how it works:
&lt;br /&gt;
&lt;br /&gt;
We backup using rsync. This way the 'old' files are not being transferred.
&lt;br /&gt;
&lt;br /&gt;
Every hour the script loops through each repository name and does the following:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Checks if the *&lt;em&gt;.latest&lt;/em&gt; file exists in the &lt;em&gt;svn-latest&lt;/em&gt; folder. If no, then it sets the &lt;em&gt;LASTDUMP&lt;/em&gt; variable to 0.&lt;/li&gt;
&lt;li&gt;If the file exists, it reads it and obtains the number stored in that file. It then stores that number incremented by 1 in the &lt;em&gt;LASTDUMP&lt;/em&gt; variable.&lt;/li&gt;
&lt;li&gt;Checks the number of the latest revision and stores it in the &lt;em&gt;LASTVERSION&lt;/em&gt; variable&lt;/li&gt;
&lt;li&gt;It loops through the repository, dumps each revision (&lt;em&gt;LASTDUMP&lt;/em&gt; to &lt;em&gt;LASTVERSION&lt;/em&gt;) and compresses it&lt;/li&gt;
&lt;/ol&gt;
This method creates new files every hour so long as new code has been added in each repository via the checkin process. The rsync command will then pick only the new files and nothing else, therefore the data transferred is reduced to a bare minimum allowing easily for hourly external backups. With this method we can also restore a single revision in a repository if we need to.
&lt;br /&gt;
&lt;br /&gt;
The script that achieves that is as follows:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="bash" line="1"&gt;#!/bin/bash

# Grab listing of folders and dump each
# repository accordingly

SVNFLD="/var/svn"
BACKUPFLD="/backup"
CHECKFLD=$BACKUPFLD/svn-latest

for i in $(ls -1v $SVNFLD); do
    if [ $i != 'conf' ]; then
        # Find out what our 'start' will be
        if [ -f $CHECKFLD/$i.latest ]
        then
            LATEST=$(cat $CHECKFLD/$i.latest)
            LASTDUMP=$LATEST+1
        else
            LASTDUMP=0
        fi

        # This is the 'end' for the loop
        LASTREVISION=$(svnlook youngest $SVNFLD/$i/)

        for ((r=$LASTDUMP; r&amp;lt; =$LASTREVISION; r++ )); do
            svnadmin dump $SVNFLD/$i/ --revision $r &amp;gt; $BACKUPFLD/$i-$r.svn.dump
            tar cvfz $BACKUPFLD/svn/$i-$r.tgz $BACKUPFLD/$i-$r.svn.dump
            rm -f $BACKUPFLD/$i-$r.svn.dump
            echo $r &amp;gt; $CHECKFLD/$i.latest
        done
    fi
done&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;
You must &lt;strong&gt;always&lt;/strong&gt; backup your data. The frequency is dictated by the rate that your data updates and how critical your data is. I hope that the methods presented in this blog post will complement your programming and source control should you choose to adopt them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-1642939403445780163?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/zj6PNLqKadw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/1642939403445780163/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/08/subversion-backup-how-to.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/1642939403445780163?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/1642939403445780163?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/zj6PNLqKadw/subversion-backup-how-to.html" title="Subversion Backup [How-To]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-NmcW5e17XbE/Tr1mJtrS3mI/AAAAAAAAFtE/pfdFLYyrku4/s72-c/online-backup.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/08/subversion-backup-how-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cFQXwyfip7ImA9WhRSEE4.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-2324093775228311902</id><published>2010-06-21T12:31:00.000-04:00</published><updated>2011-11-11T13:10:10.296-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T13:10:10.296-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Review" /><category scheme="http://www.blogger.com/atom/ns#" term="Froyo" /><category scheme="http://www.blogger.com/atom/ns#" term="Information" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="Google" /><category scheme="http://www.blogger.com/atom/ns#" term="Nexus One" /><title>Android 2.2 (Froyo) [Review]</title><content type="html">&lt;b&gt;Android 2.2 (Froyo)
&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-G5f0ICcJIQk/Tr1dqhQOY4I/AAAAAAAAFqM/cfTM3XIZdRc/s1600/android.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-G5f0ICcJIQk/Tr1dqhQOY4I/AAAAAAAAFqM/cfTM3XIZdRc/s1600/android.png" /&gt;&lt;/a&gt;&lt;/div&gt;
The newest version of the Android Operating System has been codenamed Froyo (as in Frozen&amp;nbsp;Yogurt).
&lt;br /&gt;
&lt;br /&gt;
Although I have heard of the name, I was not following very closely the development of the said OS, so I did not know what to expect. The &lt;a href="http://youtu.be/IY3U2GXhz44"&gt;presentation on Day 2 at Google I/O&lt;/a&gt; was more than impressive so I had to get my hands on it :)
&lt;br /&gt;
&lt;br /&gt;
After the GoogleIO presentation, I was regularly checking (&lt;em&gt;Settings – About Phone – System Updates&lt;/em&gt;) my phone to see what kind of version I am running and whether the update was waiting for me. Unfortunately I was disappointed every time, therefore I resigned to the idea that it will update when it is pushed to my phone.
&lt;br /&gt;
&lt;br /&gt;
A few days later though, reports on the blogosphere started appearing of users now running on Froyo. The update started rolling out so it was a matter of time for me. Most of the reports were coming from California, so if I were to look at the geography, it would take the update quite a bit of time to reach West Virginia :)
&lt;br /&gt;
&lt;br /&gt;
Through my regular research on the Internet, I found a few interesting blog posts that claimed that one can update the Nexus One without waiting for the update to be rolled out. Having nothing to lose, I decided to try it on my phone and see what happens.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Upgrade to Froyo
&lt;/b&gt;&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-64Ed9JOLRtE/Tr1dyEwakhI/AAAAAAAAFqU/ceQP7yuzhv8/s1600/froyo.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-64Ed9JOLRtE/Tr1dyEwakhI/AAAAAAAAFqU/ceQP7yuzhv8/s1600/froyo.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Android 2.2 (Froyo)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Below is how I upgraded my Nexus One to Froyo. I had a couple of failed attempts, loads of Googling but I finally managed to get it to work. Luckily a couple of days later an &lt;a href="http://lifehacker.com/5545347/get-android-22-on-your-nexus-one-without-the-wait"&gt;article&lt;/a&gt; appeared on Lifehacker which confirmed that the steps I took were the correct ones!&lt;br /&gt;
&lt;br /&gt;
I connected my Nexus One to my computer using the USB cable.
&lt;br /&gt;
&lt;br /&gt;
The phone was detected and I mounted the SD card from the phone (bring down the notification area and select the USB connection – select mount to mount the SD card)
&lt;br /&gt;
&lt;br /&gt;
When I performed these steps I had to navigate to a URL on the Android website (see&amp;nbsp;&lt;a href="http://lifehacker.com/5545347/get-android-22-on-your-nexus-one-without-the-wait"&gt;article&lt;/a&gt; on Lifehacker).
&lt;br /&gt;
&lt;br /&gt;
I copied the file and pasted it on my newly mounted drive which was the SD card of my Nexus One
&lt;br /&gt;
&lt;br /&gt;
The file is 45Mb and when the copy was completed, I unmounted the SD card from the computer initially (click the status area and select &lt;em&gt;Safely remove &amp;lt;X&amp;gt; drive&lt;/em&gt;) and then from the phone (from the notification area select &lt;em&gt;USB connection&lt;/em&gt; and select &lt;em&gt;Unmount&lt;/em&gt;)
&lt;br /&gt;
&lt;br /&gt;
The update instructions below are the original work of SimonNWalker and can be referenced &lt;a href="http://forum.androidspin.com/showthread.php?t=2631"&gt;here&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
With the update file uploaded on the Nexus One, all I had to do is shut down the device so that I can reboot it in recovery mode. The steps I took are as follows:
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-HtjcxbaRLFk/Tr1eU4raRwI/AAAAAAAAFqk/gxbEm2p0cHQ/s1600/reboot3.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="119" src="http://3.bp.blogspot.com/-HtjcxbaRLFk/Tr1eU4raRwI/AAAAAAAAFqk/gxbEm2p0cHQ/s320/reboot3.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 1: Skating Androids&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
I clicked and held the power button until the menu appeared. I selected &amp;nbsp;'Power Off', confirming that I wish the phone to power off.&lt;br /&gt;
&lt;br /&gt;
Once the phone powered off completely, I pressed and held the trackball button down and then pressed the power button. A new screen appeared (which, like myself, you probably have never seen before) with three androids on skateboards at the bottom (Figure 1) and several options at the top (Figure 2).
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-KiIPjPmBjlE/Tr1eUHX1xOI/AAAAAAAAFqc/1e1evlp7Qa4/s1600/reboot1.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-KiIPjPmBjlE/Tr1eUHX1xOI/AAAAAAAAFqc/1e1evlp7Qa4/s320/reboot1.png" width="275" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 2: Android FastBoot&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
I navigated using the power and the volume buttons. I selected the first option (&lt;strong&gt;Bootloader&lt;/strong&gt;) using the volume buttons and pressed the power button to activate it.&lt;br /&gt;
&lt;br /&gt;
A new menu appeared with the following options:
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;FASTBOOT&lt;/strong&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #339966;"&gt;&lt;strong&gt;RECOVERY&lt;/strong&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;CLEAR STORAGE&lt;/strong&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;span style="color: blue;"&gt;SIMLOCK&lt;/span&gt;&lt;/strong&gt;
&lt;br /&gt;
&lt;br /&gt;
I navigated to &lt;strong&gt;RECOVERY &lt;/strong&gt;and selected it
&lt;br /&gt;
&lt;br /&gt;
The familiar Nexus One X appeared on the screen. A few seconds later, a little android with a big exclamation mark in a triangle replaced the X.
&lt;br /&gt;
&lt;br /&gt;
The next step I took was to press simultaneously the power button and the volume up button.
&lt;br /&gt;
&lt;br /&gt;
This brought a new menu at the top (Figure 3).
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-HMwSuJ_Jb8I/Tr1e3y86f0I/AAAAAAAAFqs/lvnukVSG-Os/s1600/recovery2.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="119" src="http://2.bp.blogspot.com/-HMwSuJ_Jb8I/Tr1e3y86f0I/AAAAAAAAFqs/lvnukVSG-Os/s320/recovery2.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 3: Recovery&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
The options available were:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;reboot system now&lt;/li&gt;
&lt;li&gt;apply sdcard:update.zip&lt;/li&gt;
&lt;li&gt;wipe data/factory reset&lt;/li&gt;
&lt;li&gt;wipe cache partition&lt;/li&gt;
&lt;/ul&gt;
Using the trackball, I navigated to the second option and pressed the trackball button down.
&lt;br /&gt;
&lt;br /&gt;
At this point the update started and some information was flashing on the screen for a while, where some files were patched, some deleted, new ones copied and others replaced accordingly. The whole process took roughly 5 minutes from start to finish.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Features that I found&lt;/b&gt;&lt;br /&gt;
&lt;blockquote&gt;
&lt;em&gt;Please note that these are my own observations. Some of the features here might have been present in the previous version of Android (Eclair) and I simply did not notice them. If that is the case please let me know and I will correct the post accordingly.&lt;/em&gt;&lt;/blockquote&gt;
&lt;b&gt;&lt;i&gt;Phone search (Search throughout the phone itself)&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-VEcxKs_UKtU/Tr1fgHkswqI/AAAAAAAAFq0/xf1EoIIPRzc/s1600/search_phone.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="309" src="http://3.bp.blogspot.com/-VEcxKs_UKtU/Tr1fgHkswqI/AAAAAAAAFq0/xf1EoIIPRzc/s320/search_phone.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 4: Phone Search&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
This is one of the updates that I just love. Froyo allows you to search a lot of content that is stored on your phone. The content includes your contacts, sms messages, applications, twitter feeds and many more. With all this power it is very easy to find the information you are looking for with the press of a few keys on the virtual keyboard (Figure 4).&lt;br /&gt;
&lt;br /&gt;
Since "&lt;em&gt;with great power comes great responsibility&lt;/em&gt;", Froyo allows you to select what can be searched (Figure 5). Go to &lt;em&gt;Settings - Search - Searchable Items&lt;/em&gt; and you will find the following options:
&lt;br /&gt;
&lt;br /&gt;
- Web (web search, bookmarks and browser history)
&lt;br /&gt;
&lt;br /&gt;
- Aldiko (only if you have it installed)
&lt;br /&gt;
&lt;br /&gt;
- Apps (names of installed applications)
&lt;br /&gt;
&lt;br /&gt;
- Contacts (names of your contacts)
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-4NgpeeO9HnU/Tr1fw0dK64I/AAAAAAAAFq8/tAOlZqhtJ3Q/s1600/search_areas.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="252" src="http://4.bp.blogspot.com/-4NgpeeO9HnU/Tr1fw0dK64I/AAAAAAAAFq8/tAOlZqhtJ3Q/s320/search_areas.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 5: Search Areas&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
- Finance (stock tickers, company names) (only if you have it installed)&lt;br /&gt;
&lt;br /&gt;
- Google Sky Map (only if you have it installed)
&lt;br /&gt;
&lt;br /&gt;
- Messaging (text in your messages)
&lt;br /&gt;
&lt;br /&gt;
- Music (artists, albums and tracks)
&lt;br /&gt;
&lt;br /&gt;
- Twitter (searchable tweets) (only if you have it installed)
&lt;br /&gt;
&lt;br /&gt;
I am sure that the search extends to other applications. Your results might vary based on the apps you have installed.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Tethering - Wi-Fi Hotspot
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-4ETXEXJXKdI/Tr1f_l4tt3I/AAAAAAAAFrE/5ot_sz_G7b4/s1600/hotspot_on.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="252" src="http://2.bp.blogspot.com/-4ETXEXJXKdI/Tr1f_l4tt3I/AAAAAAAAFrE/5ot_sz_G7b4/s320/hotspot_on.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 6: Wi-Fi Hotspot&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
When I first heard about this feature during the &lt;a href="http://youtu.be/IY3U2GXhz44"&gt;presentation of Froyo at Google I/O&lt;/a&gt;, I was really excited.&lt;br /&gt;
&lt;br /&gt;
I spend every day 3 hours on the train, where I mostly work on my notebook. Having the ability to tether my phone and work online is essential. A couple of years back when I bought my first iPhone, I managed to jailbreak it and installed &lt;a href="http://www.iphonemodem.com/"&gt;iPhoneModem&lt;/a&gt; on it to achieve the functionality that I wanted (tethering). It wasn't fancy (after all don't expect miracles with AT&amp;amp;T's EDGE network) but it worked. I could get my emails reply quickly and disconnect.
&lt;br /&gt;
&lt;br /&gt;
When I got my Nexus One, I bought &lt;a href="http://www.junefabrics.com/android/"&gt;PDA Net&lt;/a&gt; to achieve the same result. It worked too but again in a very basic mode but it was draining the battery very fast and was running the phone very hot.
&lt;br /&gt;
&lt;br /&gt;
After I upgraded to Froyo, I uninstalled &lt;a href="http://www.junefabrics.com/android/"&gt;PDA Net&lt;/a&gt; and have been working with the built in functionality ever since.
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-sAoiGdQmNzo/Tr1garpWOgI/AAAAAAAAFrU/Dvgwkc-K1nk/s1600/configure_hotspot.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="205" src="http://2.bp.blogspot.com/-sAoiGdQmNzo/Tr1garpWOgI/AAAAAAAAFrU/Dvgwkc-K1nk/s320/configure_hotspot.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 7: Configure Wi-Fi Hotspot&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
To access the Tethering options, you will need to go to &lt;em&gt;Settings - Wireless &amp;amp; Networks - Tethering &amp;amp; portable hotspot&lt;/em&gt;. The options shown on Figure 6 appear, which allow you to switch the Wi-Fi hotspot on or off. A USB tethering option also exists for those that want to keep their phone charged with the power that comes from their notebook or attached device. Once the hotspot is enabled, a blue icon appears at the top notification bar. The configuration of the hotspot is really easy and can be seen in figures 7 and 8. For those wondering why I chose the SSID of my hotspot to be one of the most infectious (Windows) viruses ever, it is exactly for that reason. Apart from the WPA2 encryption, the name itself is a&amp;nbsp;deterrent&amp;nbsp;for anyone that might get ideas in stealing bandwidth.&lt;br /&gt;
&lt;br /&gt;
Everything works perfectly apart from AT&amp;amp;T's EDGE network, which is really slow. The Nexus One I have can support T-Mobile's 3G network. I haven't switched to T-Mobile yet since there was no need. I fear though that I will not be able to escape the inevitable.
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-YpWF-71N6Aw/Tr1f_6p2E-I/AAAAAAAAFrM/U4x-j_Cj0HY/s1600/hotspot_settings.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-YpWF-71N6Aw/Tr1f_6p2E-I/AAAAAAAAFrM/U4x-j_Cj0HY/s320/hotspot_settings.png" width="215" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 8: Wi-Fi Hotspot settings&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
On June 2nd AT&amp;amp;T issued &lt;a href="http://www.att.com/gen/press-room?pid=4800&amp;amp;cdvn=news&amp;amp;newsarticleid=30854"&gt;a press release&lt;/a&gt; where they showed us once again that they don't give a damn about their customers since they lie, deceive and overcharge for a mediocre (at best) service. You can read the press release and draw your own conclusions but to me it seemed once again a slap in the face.&lt;br /&gt;
&lt;br /&gt;
No more unlimited data plans for new customers, yet it is not clear what will happen to existing customers such as myself. I read somewhere in the blogosphere that those plans will remain as is, but this is AT&amp;amp;T that we are talking about - the same company that claims that calls to 1-800 numbers are free yet they charge you minutes for it.
&lt;br /&gt;
&lt;br /&gt;
I have signed for the unlimited data plan, yet AT&amp;amp;T does not allow me to tether. Why? What difference does it make? They still offer the same crappy EDGE network whether I watch a YouTube video on my phone or on my computer. &amp;nbsp;The answer is in the press release. They want more money. As phones get 'smarter' they phone companies get greedier. John Gruber offers a good &lt;a href="http://daringfireball.net/2010/06/good_and_bad_regarding_att_data_plans"&gt;analysis&lt;/a&gt; of the new AT&amp;amp;T data plans.
&lt;br /&gt;
&lt;br /&gt;
I do not know how this will evolve but I will definitely continue using the Wi-Fi hotspot on my train ride, whether this will be with AT&amp;amp;T or T-Mobile. Perhaps if I change to T-Mobile I will be able to have better coverage. AT&amp;amp;T in West Virginia is not the greatest carrier. Notable is a recent phone conversation that I had with my wife while I was driving (I am wearing the headsets btw) where the line dropped 9 times :(
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Phone/Web buttons at the bottom of every screen and desktop
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-nYxwKgp5_UM/Tr1hEOBqvjI/AAAAAAAAFrc/ibQfed2lW3o/s1600/mainscreen.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-nYxwKgp5_UM/Tr1hEOBqvjI/AAAAAAAAFrc/ibQfed2lW3o/s320/mainscreen.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 9: Phone - Web buttons&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
This was something that was needed in my opinion (Figure 9). I was pressing way too many buttons to get to the phone, especially if I was not on the main screen. This little shortcut is very well received and thought of. I do not think that there is enough space for an additional 2 buttons (for the future release of Android) but you never know.&lt;br /&gt;
&lt;br /&gt;
Perhaps a future version will allow you to customize those buttons.
&lt;br /&gt;
&lt;br /&gt;
Android development though has to be very cautious when releasing functionality. I am sure that Apple is checking everything that Android does with a microscope. With their enormous patent book near by, they will not hesitate to sue Android (or Google for that matter) for patent&amp;nbsp;infringement (see &lt;a href="http://www.engadget.com/2010/03/02/apple-sues-htc-for-infringing-20-iphone-patents/"&gt;Apple sues HTC&lt;/a&gt;).
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;More accounts to sync with
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-wM9jvNPNnaQ/Tr1hR89elYI/AAAAAAAAFrk/w952WgMrAbk/s1600/syncaccounts.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-wM9jvNPNnaQ/Tr1hR89elYI/AAAAAAAAFrk/w952WgMrAbk/s320/syncaccounts.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 10: Sync Accounts&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Another area that I noticed improvements, is the synchronization of the online accounts with the phone (Figure 10).&lt;br /&gt;
&lt;br /&gt;
This area can be accessed via &lt;em&gt;Settings - Accounts &amp;amp; sync settings&lt;/em&gt;.
&lt;br /&gt;
&lt;br /&gt;
I noticed that not only my regular GMail and Google Apps accounts appear but also YouTube as well as Twitter. I have installed the official Twitter application so I am pretty sure that this synchronization appears because of that application.
&lt;br /&gt;
&lt;br /&gt;
I have not tried it with Seesmic or any other twitter application, so if you have any additional information please let me know and I will modify this post accordingly.
&lt;br /&gt;
&lt;br /&gt;
I would also be very interested to know which other applications offer synchronization capabilities or take advantage of Android's synchronization API. If you have any other applications that synchronize on your phone, please let me know and I will include it in this post too.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Easy account switch (Email)
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-SLxVoUGa7w4/Tr1hgcEo8SI/AAAAAAAAFrs/clnVkhtdemU/s1600/emailaccountselection1.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="182" src="http://3.bp.blogspot.com/-SLxVoUGa7w4/Tr1hgcEo8SI/AAAAAAAAFrs/clnVkhtdemU/s320/emailaccountselection1.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 11: Email Account Switch&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
When I &lt;a href="http://www.niden.net/2010/02/from-iphone-to-nexus-one-review/"&gt;switched&lt;/a&gt; from an iPhone to an Android based phone, certain things were just "not right", not because there was something wrong with them - it was how I was used to things being done. One of those areas was the email. With the iPhone I was used to a traditional listing of accounts and then once something was selected I would go into the folders and then emails. If I wanted to change accounts I would have to go back two steps and then enter the account that I wanted.&lt;br /&gt;
&lt;br /&gt;
This seems a very logical approach and it is easy to get used to. Although the Android has a better email management interface, it lacked the ability to quickly switch accounts and thus not spend time tapping away going back or forth. In that area the iPhone &lt;em&gt;was &lt;/em&gt;better. Note the was. It was not because the user will tap less times, but because you would tap the back button twice which was located in the same area of the screen at all times. For the Android you had to press the menu button and then select Accounts. This was again the same amount of steps but the iPhone approach felt more natural.
&lt;br /&gt;
&lt;br /&gt;
With Froyo a new button appears at the top right of your email screen which will allow you to quickly go to the account selection screen. This effectively reduces the steps by one.
&lt;br /&gt;
&lt;br /&gt;
Analyzing briefly my emails, I can say that on average I receive 25 emails on my personal account and 35 on my business (I chose the two accounts that I get the most traffic). So if in theory I get two emails every time I check my email, that would mean that I am checking my phone 12 - 17 times a day (assuming again that I get the batches of emails on both accounts at the same time). It would therefore be safe to assume that I check my emails 15 times a day where I need to switch from one account to another.
&lt;br /&gt;
&lt;br /&gt;
So the math gives us:
&lt;br /&gt;
&lt;table style="width: 100%;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;strong&gt; Taps &lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;strong&gt; Average Email Checks per Day&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;strong&gt; Week &lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;strong&gt; Month &lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;strong&gt; Year &lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iPhone&lt;/td&gt;
&lt;td style="text-align: center;"&gt;2&lt;/td&gt;
&lt;td style="text-align: center;"&gt;15&lt;/td&gt;
&lt;td style="text-align: center;"&gt;210&lt;/td&gt;
&lt;td style="text-align: center;"&gt;900&lt;/td&gt;
&lt;td style="text-align: center;"&gt;10,950&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Android&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;td style="text-align: center;"&gt;15&lt;/td&gt;
&lt;td style="text-align: center;"&gt;105&lt;/td&gt;
&lt;td style="text-align: center;"&gt;450&lt;/td&gt;
&lt;td style="text-align: center;"&gt;5,475&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
Clearly with the above I am using now half of the screen taps than I used to with Android Eclair or with the iPhone. However the this rough calculation shows how much I was tapping in the past prior to Froyo. Goodbye RSI. :)
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Colored labels in your email (like GMail)
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-yUIz7IbA-iY/Tr1hrhRXBFI/AAAAAAAAFr0/_qcS1AmcfBg/s1600/coloredlabels.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-yUIz7IbA-iY/Tr1hrhRXBFI/AAAAAAAAFr0/_qcS1AmcfBg/s320/coloredlabels.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 12: Email Colored Labels&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
If you are like me and use Google Apps or GMail, you are by now accustomed to the colored labels on your emails, that you don't know what you have been doing without them all this time.&lt;br /&gt;
&lt;br /&gt;
With Froyo, this functionality is now available in my mobile device allowing me to visually identify emails of high interest.
&lt;br /&gt;
&lt;br /&gt;
For instance, Figure 12 shows my setup. As you can see I mark clients with a green label color and financial institutions (bills mainly) with a red color. When an email reaches my mailbox and is automatically labeled due to a relevant filter, I can easily identify its importance using this color coding.
&lt;br /&gt;
&lt;br /&gt;
Having this functionality on my mobile device is invaluable!
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Easier navigation between emails - New &amp;lt; &amp;gt; buttons appear on the phone to get you from email to email
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Another huge improvement in the navigation part as far as emails are concerned came in the screen where I read a specific email.&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-eT638dbx-Js/Tr1iEgUVgFI/AAAAAAAAFr8/OqfQxYHa-nU/s1600/emailleftrightbuttons.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-eT638dbx-Js/Tr1iEgUVgFI/AAAAAAAAFr8/OqfQxYHa-nU/s320/emailleftrightbuttons.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 13: Email Navigation&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
There are two extra buttons at the bottom of that screen which allow navigation to the previous or next message (Figure 13).
&lt;br /&gt;
&lt;br /&gt;
Another great tap saving feature!
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Better voice recognition
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I had some problems with this feature from time to time primarily due to my accent – a blend of Greek – English British – German and English American. After a few tries on the new system, I can say that there is improvement since it recognized now queries that it had failed in the past.
&lt;br /&gt;
&lt;br /&gt;
The voice search will probably never be able to detect everything that everyone is saying due to the different accents and voices of people but it is getting pretty close to perfect in my case.
&lt;br /&gt;
&lt;br /&gt;
One thing that I love about voice search is the voice navigation. I have purchased the &lt;a href="http://www.google.com/support/android/bin/answer.py?hl=en&amp;amp;answer=178146"&gt;car dock&lt;/a&gt; for my Nexus One and I use the voice navigation almost everywhere I go. Understanding that I want to go to Rockville, MD instead of Rock Creek is awesome!
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Marketplace – Update all, autoupdate for each application
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-x4utcp1_yU4/Tr1iWqNMVJI/AAAAAAAAFsE/i_z_DSx2OY0/s1600/uploadall.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-x4utcp1_yU4/Tr1iWqNMVJI/AAAAAAAAFsE/i_z_DSx2OY0/s320/uploadall.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 14: Update All&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
This feature was missing and was probably one of the ones that were mostly requested by the users. The &lt;strong&gt;Update All&lt;/strong&gt; to the installed applications.&lt;br /&gt;
&lt;br /&gt;
Luckily the Android developers have heard our pleas and Froyo now features an &lt;strong&gt;Update All&lt;/strong&gt; button at the bottom of the &lt;em&gt;Downloads &lt;/em&gt;section in the &lt;em&gt;Marketplace &lt;/em&gt;application (Figure 14).
&lt;br /&gt;
&lt;br /&gt;
Adding to this functionality, the user now has the ability to automatically update selected (or all) applications. When clicking on one of the applications to update, a checkbox appears which allows for automatic updates. If the checkbox is checked, the next time the selected application has an update, the phone will download it and install it.
&lt;br /&gt;
&lt;br /&gt;
There will always be a notification regarding the action in the notification area, but unless you know where the application is coming from (and you trust the source) you should keep this checked off.&amp;nbsp;I know I might be getting a bit paranoid here but that is what I did.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Different notification for Text Messages (trackball)
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I am not sure if this existed in Eclair but I just noticed it. When an email arrives, the trackball will start glowing briefly in regular intervals with a white color to visually notify me about the email(s) waiting for me.
&lt;br /&gt;
&lt;br /&gt;
If I receive a Google Voice message though, the trackball will still start glowing but this time it will be with a green color. This way I know that a text message is waiting for me.
&lt;br /&gt;
&lt;br /&gt;
I have sent a text message to my AT&amp;amp;T number and did see the trackball glowing but this time it was only white. It appears that the green trackball notification is a feature of Google Voice on Froyo or again it was always a Google Voice feature and I hadn't noticed, at which point I am getting excited for nothing :)
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;New icons for USB Connect/Disconnect and USB debugging
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: left;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-OtnZT6dJt50/Tr1ijHZHZ3I/AAAAAAAAFsM/93BbtitA37s/s1600/usbdebuggingicon.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-OtnZT6dJt50/Tr1ijHZHZ3I/AAAAAAAAFsM/93BbtitA37s/s1600/usbdebuggingicon.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 15: USB Debugging&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
These ones I loved them the first time I saw them. If &amp;nbsp;USB debugging is enabled &amp;nbsp;(&lt;em&gt;Settings - Applications - Development - USB Debugging&lt;/em&gt;), the minute the phone is connected to the computer using the USB cable, a new icon will appear in the notification area (Figure 15). It appears that it is an android bug of sorts :)&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-LdR4lS4m8rY/Tr1i4IlSxYI/AAAAAAAAFsc/jXQ8d-tb8JY/s1600/usbon.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-LdR4lS4m8rY/Tr1i4IlSxYI/AAAAAAAAFsc/jXQ8d-tb8JY/s320/usbon.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 16: USB Off&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-nIhXdvYyn1Q/Tr1i18IOrBI/AAAAAAAAFsU/ZKMeWUKNHic/s1600/usboff.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-nIhXdvYyn1Q/Tr1i18IOrBI/AAAAAAAAFsU/ZKMeWUKNHic/s320/usboff.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 17: USB On&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
When the phone is connected to the computer via the USB cable, the user has the ability to use the SD card as a storage device. Once the relevant entry in the notification bar is tapped, the screen with the "Turn on USB storage" will appear. If I switch the USB storage on, the screen changes slightly (Figures 16 and 17).
&lt;br /&gt;
&lt;br /&gt;
These were two really cool (in my view) new screens that engage the user even more in exploring their device!
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Camera control
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-zhJDIkzzWEY/Tr1jrDTyDiI/AAAAAAAAFsk/ntkXnealsZ4/s1600/camera_controls.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-zhJDIkzzWEY/Tr1jrDTyDiI/AAAAAAAAFsk/ntkXnealsZ4/s320/camera_controls.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 18: Camera Controls&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
A new enhancement appeared in the Camera application (Figure 18).&lt;br /&gt;
&lt;br /&gt;
The new menu that changes position based on the orientation of your phone (horizontal or vertical) allow for zooming, flash control, white balance control, geolocation and exposure.
&lt;br /&gt;
&lt;br /&gt;
The options available are:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Zoom: 1x, 1.2x, 1.4x, 1.7x, 2x&lt;/li&gt;
&lt;li&gt;Flash mode: Auto, On, Off&lt;/li&gt;
&lt;li&gt;White balance: Auto, Incandescent, Daylight, Fluorescent, Cloudy&lt;/li&gt;
&lt;li&gt;Store location: Off, On&lt;/li&gt;
&lt;li&gt;Focus mode: Auto, Infinity&lt;/li&gt;
&lt;li&gt;Exposure: -2, -1, 0, +1, +2&lt;/li&gt;
&lt;/ul&gt;
Unfortunately these controls only appear when taking photos and not when shooting video. I am sure however that this functionality (and more) will be extended to the video capturing aspect of the camera application.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Select text
&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Yk9sTLglaKM/Tr1j6p0RjRI/AAAAAAAAFss/n-zc94K8kqM/s1600/selecttext.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-Yk9sTLglaKM/Tr1j6p0RjRI/AAAAAAAAFss/n-zc94K8kqM/s320/selecttext.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 19: Select Text&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
This is an area where the iPhone was far better than the Eclair and unfortunately still is with Froyo. The gap though has decreased significantly.&lt;br /&gt;
&lt;br /&gt;
With Froyo I can now select text from say an email and paste it somewhere else - even a different application. The &lt;strong&gt;Select Text&lt;/strong&gt; option is hidden under the &lt;strong&gt;More&lt;/strong&gt; menu button and once selected, it creates a small mouse pointer. That is the start of where it will start selecting (Figure 20).
&lt;br /&gt;
&lt;br /&gt;
I simply point to the top left area I want to copy from and drag my finger diagonally to end up at the bottom right of the area I want to select. This will select the text in a very appealing pink color and as soon as I lift my finger from the screen it will copy the text on the keyboard (Figure 21).
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-AC-IiVyyNgg/Tr1j8fYo7EI/AAAAAAAAFs0/y6EkHQGIedU/s1600/select_text_1.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="115" src="http://1.bp.blogspot.com/-AC-IiVyyNgg/Tr1j8fYo7EI/AAAAAAAAFs0/y6EkHQGIedU/s320/select_text_1.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 20: Mouse pointer&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
The technique on the iPhone is better but not by much - as I wrote the gap has decreased significantly. On the iPhone you have a magnifying glass where you can pinpoint exactly where you want to start copying (or inserting text - same functionality).
&lt;br /&gt;
&lt;br /&gt;
Again unfortunately this functionality (the one with the magnifying glass for selecting text) is patented by Apple Inc. and will not be seen on an Android based phone but I am sure that the Android developers will come up with something that will give us the same if not better user experience.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;FLASH Support&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Steve Jobs &lt;a href="http://www.apple.com/hotnews/thoughts-on-flash/"&gt;never kept a secret&lt;/a&gt; of his thoughts about Flash support on an iPhone. Although many people were hopeful that something will be worked out with Adobe in the end, Mr. Jobs shut the door on Adobe. Adobe then invested time and resources to work something out and right before they were able to release their solution Apple changed the iPhone Developer License Agreement to allow only applications written in Objective-C, C, C++ or Javascript and executed by the OS Webkit engine. Adobe &lt;a href="http://mashable.com/2010/04/09/apple-adobe-flash-ban/"&gt;had enough&lt;/a&gt; and issued a '&lt;a href="http://theflashblog.com/?p=1888"&gt;screw you apple&lt;/a&gt;' (not officially of course).
&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-WqplGrFA8Bg/Tr1kTjtMtzI/AAAAAAAAFs8/wQ89EzYqUXs/s1600/pacman.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="192" src="http://4.bp.blogspot.com/-WqplGrFA8Bg/Tr1kTjtMtzI/AAAAAAAAFs8/wQ89EzYqUXs/s320/pacman.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 22: Flash on Android - PacMan&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
The&amp;nbsp;&lt;a href="http://youtu.be/IY3U2GXhz44"&gt;presentation on Day 2 at Google I/O&lt;/a&gt; included the news that Flash will be allowed and supported on Android based phones that run Froyo (or newer versions).&lt;br /&gt;
&lt;br /&gt;
I have to admit, the first version of Flash that I installed (it is still in BETA) was really slow. However three versions later, I am happy to announce that it works as well as a desktop machine. I have not tried to load a heavy flash based website but my brother in law's website (&lt;a href="http://www.dnm.gr/"&gt;www.dnm.gr&lt;/a&gt;) loads just fine and you can see all the information that you need to see :)
&lt;br /&gt;
&lt;br /&gt;
I am sure that in the coming months we will see a lot more progress in that area.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusions
&lt;/b&gt;&lt;br /&gt;
The Android 2.2 (Froyo) is a huge step forward. It provides users with a lot of functionality that transforms &amp;nbsp;a phone to a multifunction communication device. The only thing that we are missing now is proper coverage from the national carriers (AT&amp;amp;T this one is for you) and without having to sell our first born children to pay for the monthly bills (AT&amp;amp;T this one is for you too).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Update
&lt;/b&gt;&lt;br /&gt;
There has been another blog post on &lt;a href="http://androidandme.com/"&gt;AndroidAndMe&lt;/a&gt; explaining &lt;a href="http://androidandme.com/2010/06/news/new-android-2-2-update-for-the-nexus-one-is-available-now/"&gt;how to update Froyo&lt;/a&gt; to the latest build (this one is a patch not the real thing).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Update 2010-07-04
&lt;/b&gt;&lt;br /&gt;
Happy 4th of July! It came with the update for Froyo (officially now) on my cellphone. I am now running the FFR91 build (and so does my wife).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-2324093775228311902?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/iFDw3mu-5VA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/2324093775228311902/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/06/android-22-froyo-review.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/2324093775228311902?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/2324093775228311902?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/iFDw3mu-5VA/android-22-froyo-review.html" title="Android 2.2 (Froyo) [Review]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-G5f0ICcJIQk/Tr1dqhQOY4I/AAAAAAAAFqM/cfTM3XIZdRc/s72-c/android.png" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/06/android-22-froyo-review.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMMQnw-eip7ImA9WhRSEE4.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-9090282409634711290</id><published>2010-05-31T12:21:00.000-04:00</published><updated>2011-11-11T12:28:03.252-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T12:28:03.252-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Memorial Day" /><category scheme="http://www.blogger.com/atom/ns#" term="Celebrations" /><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>2010 Memorial Day [USA][Celebrations][Personal]</title><content type="html">Today, the Memorial Day is celebrated across the USA. There are similar celebrations in Greece, not the same day as in the US but remembering and honoring the veterans for their sacrifices for the freedoms we and our families enjoy.

I received an email this morning which I thought was too precious to be archived in my mail folders. Since I hate mass mailing and chain emails, I thought I would duplicate the email here for my archiving but also for everyone else to see.

Please note that I am not the original author of the email and I do not know if it has appeared as a blog post or an article someplace. I do not own the images presented below either so if there is a copyright issue, please let me know and I will remove them immediately. If you know who the original author is, please let me know so that I can give them the mention they deserve.
&lt;br /&gt;
&lt;h2 style="text-align: center;"&gt;


&lt;strong&gt;&lt;span style="color: navy;"&gt;MEMORIAL DAY&lt;/span&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;div style="text-align: center;"&gt;
It is the&amp;nbsp;VETERAN,&amp;nbsp;not the preacher,&amp;nbsp;who has given us freedom of religion.&lt;/div&gt;
&lt;div style="text-align: center;"&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-THIK0BPBU30/Tr1aDEfoHvI/AAAAAAAAFpc/ixJa9ceupP4/s1600/pic18762.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="228" src="http://3.bp.blogspot.com/-THIK0BPBU30/Tr1aDEfoHvI/AAAAAAAAFpc/ixJa9ceupP4/s320/pic18762.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-eIn3mxu_F4g/Tr1aERs7czI/AAAAAAAAFqE/qbHAOcpALB0/s1600/pic32591.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="236" src="http://3.bp.blogspot.com/-eIn3mxu_F4g/Tr1aERs7czI/AAAAAAAAFqE/qbHAOcpALB0/s320/pic32591.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
It is&amp;nbsp;the VETERAN,&amp;nbsp;not the reporter,&amp;nbsp;who has given us freedom of the press.&lt;/div&gt;
&lt;div style="text-align: center;"&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-IXJ87Dv7Tjk/Tr1aEKoa35I/AAAAAAAAFp8/oxRPnxu50Ik/s1600/pic27624.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="228" src="http://2.bp.blogspot.com/-IXJ87Dv7Tjk/Tr1aEKoa35I/AAAAAAAAFp8/oxRPnxu50Ik/s320/pic27624.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
It is&amp;nbsp;the VETERAN,&amp;nbsp;not the poet,&amp;nbsp;who has given us freedom of speech.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-f8FnKLCN3Vo/Tr1aC35RY0I/AAAAAAAAFpU/W4Amv4NuLPw/s1600/pic17410.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="212" src="http://3.bp.blogspot.com/-f8FnKLCN3Vo/Tr1aC35RY0I/AAAAAAAAFpU/W4Amv4NuLPw/s320/pic17410.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-8XCdaRQ-M2A/Tr1aDjF8NfI/AAAAAAAAFpg/t6QQAmCxkIc/s1600/pic20537.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="214" src="http://1.bp.blogspot.com/-8XCdaRQ-M2A/Tr1aDjF8NfI/AAAAAAAAFpg/t6QQAmCxkIc/s320/pic20537.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
It is&amp;nbsp;the VETERAN,&amp;nbsp;not the campus organizer,&amp;nbsp;who has given us freedom to assemble.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-8MWoRvWwesU/Tr1aCXr2XAI/AAAAAAAAFo8/mXCznUllLZE/s1600/pic01655.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="225" src="http://4.bp.blogspot.com/-8MWoRvWwesU/Tr1aCXr2XAI/AAAAAAAAFo8/mXCznUllLZE/s320/pic01655.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
It is&amp;nbsp;the VETERAN,&amp;nbsp;not the lawyer,&amp;nbsp;who has given us the right to a fair trial.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-iq8jyu0QvdA/Tr1aC-DvcwI/AAAAAAAAFpM/1-NxP5D-1bE/s1600/pic06359.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="227" src="http://1.bp.blogspot.com/-iq8jyu0QvdA/Tr1aC-DvcwI/AAAAAAAAFpM/1-NxP5D-1bE/s320/pic06359.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
It is&amp;nbsp;the VETERAN,&amp;nbsp;not the politician,&amp;nbsp;Who has given us the right to vote.
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-wK0DDhUpiPo/Tr1aDkNsicI/AAAAAAAAFpo/rl01HePlEg8/s1600/pic21548.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-wK0DDhUpiPo/Tr1aDkNsicI/AAAAAAAAFpo/rl01HePlEg8/s320/pic21548.jpg" width="317" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
It is the&amp;nbsp;VETERAN who&amp;nbsp;salutes the Flag,&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-Niee-M0y6jo/Tr1aDyTqEYI/AAAAAAAAFpw/YJW9WSN0EtY/s1600/pic27595.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-Niee-M0y6jo/Tr1aDyTqEYI/AAAAAAAAFpw/YJW9WSN0EtY/s320/pic27595.jpg" width="219" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&amp;nbsp;

It is&amp;nbsp;the&amp;nbsp;VETERAN&amp;nbsp;who serves&amp;nbsp;under the Flag,&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-aA1xF7c7YLw/Tr1aChU_gRI/AAAAAAAAFpE/KacHLbCuvYI/s1600/pic04041.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="261" src="http://3.bp.blogspot.com/-aA1xF7c7YLw/Tr1aChU_gRI/AAAAAAAAFpE/KacHLbCuvYI/s320/pic04041.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #20124d;"&gt;ETERNAL&amp;nbsp;REST GRANT THEM O LORD,&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #20124d;"&gt;AND LET PERPETUAL LIGHT SHINE UPON&amp;nbsp;THEM.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
No matter what the country of your origin, there are always some people that step up in difficult situations. Those men and women gladly give their lives for the better good, so that others can enjoy a better future. Those people are the Veterans that we must always remember and honor.&lt;br /&gt;
&lt;br /&gt;
There is plenty of material regarding Memorial Day on the Internet. A site worth visiting is &lt;a href="http://www.usmemorialday.org/"&gt;http://www.usmemorialday.org/&lt;/a&gt; and two videos worth watching on YouTube are&amp;nbsp;&lt;a href="http://youtu.be/afd_sDNYbpY"&gt;http://youtu.be/afd_sDNYbpY&lt;/a&gt; and &lt;a href="http://youtu.be/wK0T4pVHP28"&gt;http://youtu.be/wK0T4pVHP28&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-9090282409634711290?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/6Kd9BNMUWdg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/9090282409634711290/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/05/2010-memorial-day-usacelebrationsperson.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/9090282409634711290?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/9090282409634711290?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/6Kd9BNMUWdg/2010-memorial-day-usacelebrationsperson.html" title="2010 Memorial Day [USA][Celebrations][Personal]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-THIK0BPBU30/Tr1aDEfoHvI/AAAAAAAAFpc/ixJa9ceupP4/s72-c/pic18762.gif" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/05/2010-memorial-day-usacelebrationsperson.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMGSHs4fip7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-3779124864894686742</id><published>2010-05-18T11:59:00.000-04:00</published><updated>2011-11-11T15:47:09.536-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T15:47:09.536-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>Update [Personal]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-3S214dx8LTA/Tr1uVH87WjI/AAAAAAAAFu0/21RSIwRGjjc/s1600/update.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="283" src="http://4.bp.blogspot.com/-3S214dx8LTA/Tr1uVH87WjI/AAAAAAAAFu0/21RSIwRGjjc/s320/update.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
It has been more than a month since I last blogged. I started a couple of blog posts but they are mostly ideas written down than structured posts, hence they are in my draft folder.
&lt;br /&gt;
&lt;br /&gt;
Throughout this month and change that I have been absent (I know my favorite readers have missed me - all 5 of you and no mom you are not in that count) many things have happened that made me sit back and reflect on what I have and what I have lost.
&lt;br /&gt;
&lt;br /&gt;
As any other family living the American Dream, we outgrew our current car capacity and therefore had to purchase a minivan!&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: left;"&gt;
&lt;/div&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-G1tuvfJlhok/Tr1YHnnyDNI/AAAAAAAAFnQ/2vEh3AL3diE/s1600/2010_dodge_grand_caravan.jpeg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="180" src="http://4.bp.blogspot.com/-G1tuvfJlhok/Tr1YHnnyDNI/AAAAAAAAFnQ/2vEh3AL3diE/s320/2010_dodge_grand_caravan.jpeg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;2010 Dodge Grand Caravan&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
We decided to get the &lt;a href="http://www.dodge.com/en/2010/grand_caravan/"&gt;Dodge Grand Caravan&lt;/a&gt; mostly due to the fact that it looks great and also because we had a Dodge for the past 10 years and the features on it were exactly what we needed. The new vehicle would accommodate easily ourselves, our son Dimosthenis, our 2 year old Golden Retriever Hairy and our soon to arrive daughter Zoe, with plenty of room for our 'stuff' when going on short trips.
&lt;br /&gt;
&lt;br /&gt;
So the weekend after we purchased the minivan we decided to drive to Delaware, where my in-laws live to surprise them. They always love it when Dimosthenis visits so we thought it would be a good idea to spend the weekend there. We woke up relatively early, packed our stuff and were on our way to the beach. It was when we stopped to fill the minivan up when we heard the news.
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&lt;/div&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-4D58JT3YRZ0/Tr1YJTLw41I/AAAAAAAAFnY/1c7Yk3d5Ehc/s1600/jimanddimos.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-4D58JT3YRZ0/Tr1YJTLw41I/AAAAAAAAFnY/1c7Yk3d5Ehc/s320/jimanddimos.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Jim and Dimosthenis&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Jim - my brother in law - had passed in his sleep. It was all a bad dream, I did not want to believe it but there was no denying it.
&lt;br /&gt;
&lt;br /&gt;
James Ruel Poston died peacefully in his sleep on March 20th. Cause: Heart condition.
&lt;br /&gt;
&lt;br /&gt;
We turned back home, let Hairy in the house (our neighbor was going to look after him) and headed straight to Baltimore where Jim's apartment was. The whole family gathered there, &amp;nbsp;and inevitably we had to deal with the mundane logistics of the situation i.e. moving all of his stuff out of the apartment and cleaning it. It took a great deal of effort do do so and the psychological burden of the event did not help. A few days later, exhausted physically and psychologically we managed to complete the task.
&lt;br /&gt;
&lt;br /&gt;
Jim's obituary reads:
&lt;br /&gt;
&lt;blockquote&gt;
James Reuel Poston, 40, died Sunday, March 20, 2010, peacefully in his home.

James was born April 11, 1969 in Washington, D.C. to Joy and Phillip Poston. He studied sports broadcast journalism in college – a passion he carried with him throughout his life. Family and friends will always remember his wonderful sense of humor and strong commitment to those he loved.

James is survived by his parents, Joy and Steve Smith and Phillip and Susan Poston; grandmother Mary “YiaYia” Pantazis; his sister Tia and brother-in law Nikolaos; brothers Jonathan and Peter; sisters Lauren and Abigail; and nephew Dimosthenis.

A funeral service was held Thursday, March 25, at St. George Greek Orthodox Church, 8805 Coastal Highway, Ocean City, Md. Interment was in Bethel Cemetery, Lewes. In lieu of flowers, make donations to the Cal Ripken Sr. Foundation, &lt;a href="http://ripkenfoundation.org/"&gt;ripkenfoundation.org&lt;/a&gt;.

Arrangements by Watson Funeral Home, Millsboro.&lt;/blockquote&gt;
On Thursday, 25th of March 2010, Jim was buried in Lewes, DE. Family and friends gathered to say goodbye for the last time.
&lt;br /&gt;
&lt;br /&gt;
Jim will never be forgotten. His goofiness, smile, kind heart, unconditional love towards his nephew and infinite knowledge about sports will always be the things that defined him.
&lt;br /&gt;
&lt;br /&gt;
After the 40 day service following his passing, we started getting ready for a new arrival, our daughter Zoe Dimitra Dimopoulos.
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: left;"&gt;
&lt;/div&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-BHHXEVo7YsQ/Tr1YHVHX7pI/AAAAAAAAFnI/Ih5vefOqG2E/s1600/2010-05-04-14.16.38.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-BHHXEVo7YsQ/Tr1YHVHX7pI/AAAAAAAAFnI/Ih5vefOqG2E/s320/2010-05-04-14.16.38.jpg" width="240" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Zoe Dimitra&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Zoe Dimitra was born at 12:06 on the 3rd of May 2010. She weighed 7lbs 11oz and was 20 inches tall. She came out screaming, but soon was calm and happy in her mother's hands. Her name means &lt;a href="http://zoeeng.com/zoedefinition.html"&gt;Life&lt;/a&gt; in Greek, and it is also the name of my mother in law. It is a tradition to name your children with the names of your parents or in-laws.&lt;br /&gt;
&lt;br /&gt;
We decided that she will have a middle name (Greeks rarely have middle names) and it is &lt;a href="http://www.google.com/search?hl=en&amp;amp;defl=en&amp;amp;q=define:Dimitra&amp;amp;ei=Hu_yS-2dIYPCNpn2jIYO&amp;amp;sa=X&amp;amp;oi=glossary_definition&amp;amp;ct=title&amp;amp;ved=0CBUQkAE"&gt;Dimitra&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
The reason we chose this middle name is to honor my recently departed brother in law Jim. His Greek name was Dimitris (it translates roughly to James in English) and Dimitra is the female version of that name. James/Dimitris was also my wife's grandfather ('pappous' in Greek), so we thought that it would be nice to remember him too this way.
&lt;br /&gt;
&lt;br /&gt;
It has been a really rough month and a half, filled with tears, sorrow, tears, joy. Life goes on and Zoe is here with us.
&lt;br /&gt;
&lt;br /&gt;
I have started taking the train again to go to work which will give me roughly 3 hours uninterrupted programming and blogging. I will finally be able to continue on some of my projects like the &lt;a href="http://www.angularjs.org/"&gt;&amp;lt;angular/&amp;gt;&lt;/a&gt; &lt;a href="http://code.google.com/p/angularbugtracker/"&gt;bug tracker&lt;/a&gt;, a blog based on &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt;, Python development and more.
&lt;br /&gt;
&lt;br /&gt;
Stay tuned!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-3779124864894686742?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/sHPV0tOnS6Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/3779124864894686742/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/05/update-personal.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/3779124864894686742?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/3779124864894686742?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/sHPV0tOnS6Y/update-personal.html" title="Update [Personal]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-3S214dx8LTA/Tr1uVH87WjI/AAAAAAAAFu0/21RSIwRGjjc/s72-c/update.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/05/update-personal.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIHQXw-cSp7ImA9WhRSEE4.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-4319279386711058499</id><published>2010-03-31T09:19:00.000-04:00</published><updated>2011-11-11T13:52:10.259-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T13:52:10.259-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Spam" /><category scheme="http://www.blogger.com/atom/ns#" term="Rant" /><category scheme="http://www.blogger.com/atom/ns#" term="Buzz" /><category scheme="http://www.blogger.com/atom/ns#" term="Google" /><category scheme="http://www.blogger.com/atom/ns#" term="Privacy" /><title>Online Privacy, Spam, Buzz, Banks and Mail [Rant]</title><content type="html">&lt;b&gt;Electronic Presence
&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-Fn2bJQQizd8/Tr1u1PtfVQI/AAAAAAAAFu8/MncIHs8q8cM/s1600/privacy-1.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="297" src="http://1.bp.blogspot.com/-Fn2bJQQizd8/Tr1u1PtfVQI/AAAAAAAAFu8/MncIHs8q8cM/s320/privacy-1.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
Everyone more or less has some sort of electronic presence. That presence can easily be seen on &lt;a href="http://www.twitter.com/nikosdimopoulos"&gt;Twitter&lt;/a&gt;, &lt;a href="http://www.facebook.com/nikos.dimopoulos.usa"&gt;Facebook&lt;/a&gt;, personal blog, &lt;a href="https://profiles.google.com/104235485963468152376"&gt;Google account&lt;/a&gt;, Buzz etc.&lt;br /&gt;
&lt;br /&gt;
What most people neglect to realize that this is only the tip of the iceberg. How about the information your bank stores about you? Isn't that an electronic/online presence? Some server contains vital information about you and your bank uses that information to identify you against someone else. If your bank provides online banking, then the Internet becomes the interface that you use to access your own personal information (mainly funds) which again is stored somewhere else.
&lt;br /&gt;
&lt;br /&gt;
The same happens when you purchase something online. Say you want to purchase flowers for your loved one. You will be probably asked to create an account with the florists's website and you will need to provide payment for the flowers. The authenticator, in this case, is some company that will check your credit card against an online record (again stored somewhere) in order to authorize the payment.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Google Buzz
&lt;/b&gt;&lt;br /&gt;
With this in mind, I have been wondering lately why all of a sudden everyone seems to be trying to stab Google, due to some mishaps with Buzz? Were the controls that Buzz had initially set correctly? You might say no here and I would have to respectfully disagree. The point is that there was the option for people to opt out, the terms of service were there for everyone to read (I am wondering who did if any) so why was something set incorrectly? Why complain if the information was available for everyone to make an intelligent and educated choice as to use the new tool or not? If you did not investigate and read all there is to it regarding Buzz then you are responsible for anything that comes with it.&lt;br /&gt;
&lt;br /&gt;
I hear already people screaming at me that this was supposed to be an &lt;strong&gt;opt-in not an opt-out&lt;/strong&gt; service. I agree and disagree there. Allow me to elaborate.
&lt;br /&gt;
&lt;br /&gt;
For starters Google offers Buzz (and &lt;a href="http://gmail.google.com/"&gt;GMail&lt;/a&gt;) for free. How come all of a sudden this free product (which mind you is of extremely high quality) became everyone's right and stopped being a privilege? Yeah sure, Google runs ads and displays them on the right side of your&amp;nbsp;&lt;a href="http://gmail.google.com/"&gt;GMail&lt;/a&gt;. That is how they offset their costs. Is anything wrong with that? I don't think so. Yet you have people that try to download special extensions to block ads, they change their signature to contain certain keywords that Google has deemed inappropriate - in short endangering everyone's use of&amp;nbsp;&lt;a href="http://gmail.google.com/"&gt;GMail&lt;/a&gt; because if it turns out to be totally not profitable for Google they will simply close down the service or start charging for it. If that happens the first people that will complain are going to be the ones that caused this i.e. the ones that were blocking ads.
&lt;br /&gt;
&lt;br /&gt;
Everyone complained about Buzz. It was not secure enough, it exposed personal information etc. If you looked closely, the choice to opt out was available. People will argue that it was not the default value but that is not the point. The option was available (and still is) and people should start reading what they sign up to. Terms and conditions exist for a reason and people should start reading that stuff and exploring the options/settings prior to signing up to something!
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;My Financial Institution
&lt;/b&gt;&lt;br /&gt;
A few days ago I got a letter from &lt;a href="http://www.flagstar.com/"&gt;Flagstar Bank&lt;/a&gt;, which is (was) my mortgage bank. It appears that they sold my mortgage to &lt;a href="http://www.everhome.com/"&gt;EverHome&lt;/a&gt; (just another mortgage company). This is a really common practice over the course of a mortgage. Thus far (6 months into my mortgage), I have changed 3 companies. I would be interested to see what will happen in the course of 30 years :).&lt;br /&gt;
&lt;br /&gt;
After receiving this notice from&amp;nbsp;&lt;a href="http://www.flagstar.com/"&gt;Flagstar Bank&lt;/a&gt;, I got a new letter from &lt;a href="http://www.everhome.com/"&gt;EverHome&lt;/a&gt; with some interesting information. The most interesting part of this documentation was the Privacy policy of&amp;nbsp;&lt;a href="http://www.everhome.com/"&gt;EverHome&lt;/a&gt;. Here is what is in store for me:
&lt;br /&gt;
&lt;blockquote&gt;
&lt;strong&gt;Do we disclose your information to non-affiliated third parties?&lt;/strong&gt;

We may disclose all of the information about you, as described above, to certain people, subject to legal restrictions, and subject to your right to ask us not to share your information. Your right to ask us not to disclose your information is referred to as your "Opt-Out Rights" and is more fully described below.

&lt;strong&gt;To what non-affiliated parties do we disclose your information?&lt;/strong&gt;

Subject to your Opt-Out Rights described below, we may disclose your nonpublic personal information to the following types of third parties:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Financial service providers, such as banks, mortgage companies, mortgage brokers, consumer credit companies, investment advisors and similar companies;&lt;/li&gt;
&lt;li&gt;Insurance providers, such as life insurance companies, credit insurance companies, hazard insurance companies, automobile insurance companies; and&lt;/li&gt;
&lt;li&gt;Other optional service providers and organizations.&lt;/li&gt;
&lt;/ul&gt;
Even if you opt-out of information sharing, we will still share information about you with certain third parties as permitted by law or regulation. This may include but not limited to, disclosing information:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;To parties assisting in servicing or processing of your loan;&lt;/li&gt;
&lt;li&gt;To our lawyers, accountants, auditors, regulators and advisors;&lt;/li&gt;
&lt;li&gt;To protect our rights relating to, and the security of, your loan, our website, or our telephone customer service center;&lt;/li&gt;
&lt;li&gt;To verify the existence or status of your loan for a third party;&lt;/li&gt;
&lt;li&gt;To companies that perform marketing servcices on our behalf, or jointly with us;&lt;/li&gt;
&lt;li&gt;To other financial institutions with whom we have joint marketing agreements; and&lt;/li&gt;
&lt;li&gt;When you ask or give us permission to do so.&lt;/li&gt;
&lt;/ul&gt;
&lt;strong&gt;Do we share your information with our affiliates?&lt;/strong&gt;

We are affiliated with several types of companies including but not limited to other financial service , such as banks, mortgage companies, and title insurance agents. Even if you exercise your Opt-Out Rights, we may share with our affiliates information about our direct transactions and experiences with you.

Subject to your Opt-Out Rights, we may share information about you obtained from third parties with our affiliates, including:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Information from your application, such as your age, gender, marital status, number of&amp;nbsp;dependents, assets, debts, income, employment information, address and the address of the property securing your loan;&lt;/li&gt;
&lt;li&gt;Information from a consumer report, including information about your credit worthiness, financial circumstances, and credit history, including any bankruptcies or foreclosures;&lt;/li&gt;
&lt;li&gt;Information to verify representations made by you, such as verification of your income, employment, and open lines of credit with others; and&lt;/li&gt;
&lt;li&gt;Information from a person about his or her employment, credit, or other relationship with you, such as your employment history with your employer, or credit history with another financial institution.&lt;/li&gt;
&lt;/ul&gt;
&lt;strong&gt;How can you Opt-Out?&lt;/strong&gt;

If you do not want us to disclose nonpublic personal information about you to nonaffiliated third parties, or if you want to limit the nonpublic personal information we may disclose to our affiliates, you may Opt-Out &amp;lt;Opt-Out information goes here including mailing address and 800 phone number&amp;gt; Please remember that even if you choose to opt-out, we will still disclose information about you as permiited by law or regulation.&lt;/blockquote&gt;
From what I have heard from friends, this is pretty much standard text for almost every mortgage company. Let's have a look a bit on a couple of interesting points and how that relates to Google and Buzz.
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;This is not the initial mortgage company. I did not allow them to do anything with my personal information. My initial mortgage company had a clause that basically said "&lt;em&gt;we are allowed to sell your mortgage and with it your information&lt;/em&gt;". So I am stuck. This new company has my personal information (vital information such as my SSN, information about my previous employment, account balances and possibly account numbers, name, credit cards, in short everything). Did my old mortgage company delete my records from their systems? Most probably no. So here I am having 2 records out there without having to lift a finger. Did the introduction of Buzz create a brand new record of all of your personal information and disclosed it/forwarded it to a brand new company?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;This is an Opt-Out policy&lt;/strong&gt;. Wait a minute!!! Why don't I see a revolution, people running on the streets of major cities with signs, crying and condemning &lt;a href="http://www.everhome.com/"&gt;EverHome&lt;/a&gt; for such&amp;nbsp;sacrilege, sending thousands of tweets, blogging about it.... condemning the company and associating them with the devil? &lt;a href="http://www.everhome.com/"&gt;EverHome&lt;/a&gt; has hundreds of thousands of customers. I never heard any complain about this! How many of those customers have&amp;nbsp;&lt;a href="http://gmail.google.com/"&gt;GMail&lt;/a&gt; accounts? Chances are quite a few. How many complained about Buzz? Probably a significant number. Did they also complain to&amp;nbsp;&lt;a href="http://www.everhome.com/"&gt;EverHome&lt;/a&gt;? Did they blog about it or tweet about it?&lt;/li&gt;
&lt;li&gt;If you carefully read the above, you will see that my whole life, all the vital information about me, can be transmitted to various other companies so long as they are affiliated to&amp;nbsp;&lt;a href="http://www.everhome.com/"&gt;EverHome&lt;/a&gt;. Do I have a saying in this? Not really. The last paragraph clearly states that even if I Opt-Out, they will release my information under certain circumstances "&lt;em&gt;Please remember that even if you choose to opt-out, we will still disclose information about you as permiited by law or regulation.&lt;/em&gt;"&lt;/li&gt;
&lt;/ol&gt;
&lt;b&gt;Who else does Opt-Out?&lt;/b&gt;&lt;br /&gt;
This post is not to bad mouth or disgrace&amp;nbsp;&lt;a href="http://www.everhome.com/"&gt;EverHome&lt;/a&gt;. Far from it. &lt;span style="text-decoration: underline;"&gt;This post is to condemn&amp;nbsp;hypocrisy&lt;/span&gt;. I have read many blogs from people condemning Google for their Opt-Out policy in Buzz - whereas it should have been Opt-In. Yeah fine, I agree to that. But then again, less than a month later Google changed their policy to an Opt-In, introduced more alerts, controls and visual effects to ensure that the user wants to Opt-In. That is Google.&lt;br /&gt;
&lt;br /&gt;
Where are the blog posts complaining about the Opt-Out policies that other companies that we use their services on a daily basis?&amp;nbsp;Did anyone bother to read the terms and conditions of say &lt;a href="http://www.verizon.net/"&gt;Verizon&lt;/a&gt;, &lt;a href="http://www.att.com/"&gt;AT&amp;amp;T&lt;/a&gt; for your cellphone, Satellite service (&lt;a href="http://www.dishnetwork.com/"&gt;Dish&lt;/a&gt;/&lt;a href="http://www.directv.com/"&gt;Direct TV&lt;/a&gt;) etc.? I dare you to check your paperwork; you will be shocked to find that almost everyone uses the Opt-Out approach and not the Opt-In.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Regular Mail
&lt;/b&gt;&lt;br /&gt;
Consider also your regular mail. Whatever the postman brings. How much junk do you really get in your mailbox, just because you got a store card, ordered once from a website and now you cannot get them to stop? My wife got a gift certificate once for a motorbike accessory store for our cousin and since then we receive this really nice magazine concerning motorbikes. We returned it rejected more than 5 times but they do not get the hint. Did we ask for it? No. Do they have the right to do that? No, but they do not care. Did anyone complain about all this? Not as much as they complained about Buzz.....&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion
&lt;/b&gt;&lt;br /&gt;
Google is not the devil. I do believe that they adhere by the "&lt;em&gt;Don't be evil&lt;/em&gt;" motto. I use their products and I am happy that I do because the quality of products offered help me do my job better. Do I read all the disclaimers and terms and conditions? Yes I do and if there is something I do not like I do not use it. If I click '&lt;em&gt;I accept the Terms&lt;/em&gt;' then I have no right to complain for something that was there and I did not read it or pay attention to it. If you don't like them, don't like their policies, do not use their products. Export your data from &lt;a href="http://gmail.google.com/"&gt;GMail&lt;/a&gt; (since Google adheres to the &lt;a href="http://www.dataliberation.org/"&gt;Data Liberation&lt;/a&gt; principles) to your computer or a different provider, delete your Google Account and stop complaining. There is a difference between making suggestions towards making a product better and bitching about something that is mostly your fault (i.e. reading Terms and Conditions and checking settings).&lt;br /&gt;
&lt;br /&gt;
I always remind myself that the free Google services are a privilege to me and not my right. Shouldn't you do the same if using those same free products?
&lt;br /&gt;
&lt;br /&gt;
Rant on!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-4319279386711058499?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/BYD9YdQQJi0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/4319279386711058499/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/03/online-privacy-spam-buzz-banks-and-mail.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/4319279386711058499?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/4319279386711058499?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/BYD9YdQQJi0/online-privacy-spam-buzz-banks-and-mail.html" title="Online Privacy, Spam, Buzz, Banks and Mail [Rant]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-Fn2bJQQizd8/Tr1u1PtfVQI/AAAAAAAAFu8/MncIHs8q8cM/s72-c/privacy-1.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/03/online-privacy-spam-buzz-banks-and-mail.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04ASHo4fip7ImA9WhRSEE4.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-7938892185280354957</id><published>2010-02-28T08:52:00.000-05:00</published><updated>2011-11-11T12:19:09.436-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T12:19:09.436-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Review" /><category scheme="http://www.blogger.com/atom/ns#" term="iPhone" /><category scheme="http://www.blogger.com/atom/ns#" term="Google" /><category scheme="http://www.blogger.com/atom/ns#" term="Nexus One" /><title>From iPhone to Nexus One [Review]</title><content type="html">References: "&lt;a href="http://www.mattcutts.com/blog/switch-iphone-to-android/"&gt;Leaving the iPhone&lt;/a&gt;" by Matt Cutts, &lt;a href="https://docs.google.com/View?id=ajmh7zht8f5f_3dbdpf6xv"&gt;Android Equivalency Table&lt;/a&gt; and "&lt;a href="http://al3x.net/2010/02/15/ubuntu-android.html"&gt;Good Things: Ubuntu and Android&lt;/a&gt;" by Alex Payne. I am pretty sure that there are other reviews and how-to's on the Internet, outlining that one of the above (or none) is the killer of the other. I am just posting what I did to switch effortlessly.
&lt;br /&gt;
&lt;br /&gt;
Homework
&lt;br /&gt;
&lt;br /&gt;
Of the applications currently installed on my iPhone, some are really very essential (i.e. email, web, podcast manager etc.) and some I can easily live without (Sportacular). Below is a list of the applications that I have listed in importance order and their counterparts in Android.
&lt;br /&gt;
&lt;table style="width: 100%;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center; width: 10%;"&gt;&lt;strong&gt;Severity&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center; width: 20%;"&gt;&lt;strong&gt;Application - iPhone&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center; width: 70%;"&gt;&lt;strong&gt;Application - Nexus One&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;Calendar&lt;/td&gt;
&lt;td&gt;Calendar (built in - syncs automatically with the account you log in)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;Google Voice&lt;/td&gt;
&lt;td&gt;Google Voice (integrates with the Nexus One so you call using your Voice number)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;GV Mobile&lt;/td&gt;
&lt;td&gt;Google Voice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;iPhoneModem&lt;/td&gt;
&lt;td&gt;PDANet ($30) or if you root your Nexus One other applications. PDANet requires Bluetooth or the USB cable, the others can hook up a WiFi connection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;iPod&lt;/td&gt;
&lt;td&gt;Listen (by Google)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;Mail&lt;/td&gt;
&lt;td&gt;Mail (built in - allows for IMAP, Exchange, POP - it also syncs easily Google based email)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;Maps&lt;/td&gt;
&lt;td&gt;Web based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;Phone&lt;/td&gt;
&lt;td&gt;Phone (built in - can be replaced by Google Voice)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;pTerm&lt;/td&gt;
&lt;td&gt;Connectbot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;Solebon&lt;/td&gt;
&lt;td&gt;Solitaire (not as advanced as the paid Solebon but it will do)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;Stanza&lt;/td&gt;
&lt;td&gt;Apparently Panda Reader is out but I could not find it. I gave up on this since I mostly work on the notebook and not longer read books on my mobile device&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;WunderRadio&lt;/td&gt;
&lt;td&gt;Streamfurious - not as good as WunderRadio but it has the stations I listen to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;H&lt;/td&gt;
&lt;td&gt;YouTube&lt;/td&gt;
&lt;td&gt;YouTube&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;Buzz&lt;/td&gt;
&lt;td&gt;Web based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;Calculator&lt;/td&gt;
&lt;td&gt;Calculator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;Camera&lt;/td&gt;
&lt;td&gt;Camera&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;CardStar&lt;/td&gt;
&lt;td&gt;Key Ring Reward Cards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;Clock&lt;/td&gt;
&lt;td&gt;Clock - does not have countdown or stopwatch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;Cycorder&lt;/td&gt;
&lt;td&gt;Camera (built in)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;FuelGauge&lt;/td&gt;
&lt;td&gt;aCar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;Google Earth&lt;/td&gt;
&lt;td&gt;Google Earth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;iTunes&lt;/td&gt;
&lt;td&gt;Android Marketplace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;Lattitude&lt;/td&gt;
&lt;td&gt;Lattitude (a lot of privacy warnings - even an email - to ensure that you want to switch it on)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;LinkedIn&lt;/td&gt;
&lt;td&gt;Droidln&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;Photos&lt;/td&gt;
&lt;td&gt;Photos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;QuickMark&lt;/td&gt;
&lt;td&gt;Barcode Scanner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;RedLaser&lt;/td&gt;
&lt;td&gt;Goggles, Barcode Scanner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;Shazam&lt;/td&gt;
&lt;td&gt;Shazam&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;TweetDeck&lt;/td&gt;
&lt;td&gt;Seesmic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;TWiT&lt;/td&gt;
&lt;td&gt;TWiT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;M&lt;/td&gt;
&lt;td&gt;VNC&lt;/td&gt;
&lt;td&gt;Remote VNC Lite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Dictionary&lt;/td&gt;
&lt;td&gt;Dictionary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Facebook&lt;/td&gt;
&lt;td&gt;Facebook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Flixster&lt;/td&gt;
&lt;td&gt;Flixter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Messages&lt;/td&gt;
&lt;td&gt;Messages (built in - integrates with Google Voice)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Notes&lt;/td&gt;
&lt;td&gt;Evernote, like a billion other note apps some of which sync to Google Docs or other similar services, Tomdroid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Pregnancy&lt;/td&gt;
&lt;td&gt;A lot of applications, Pregnancy Assistant one that comes close to Pregnancy for the iPhone - either way I won't need this after May (I think :))&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Sears2Go&lt;/td&gt;
&lt;td&gt;Sears2Go&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Skype&lt;/td&gt;
&lt;td&gt;Fring, I also use Skype Go so no problem for me there&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;SnapTell&lt;/td&gt;
&lt;td&gt;Goggles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Sportacular&lt;/td&gt;
&lt;td&gt;Scoreboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Stocks&lt;/td&gt;
&lt;td&gt;Finance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;TrafficInfo&lt;/td&gt;
&lt;td&gt;INRIX Traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;USAA&lt;/td&gt;
&lt;td&gt;USAA Mobile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Voice Memos&lt;/td&gt;
&lt;td&gt;Google Voice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Weather&lt;/td&gt;
&lt;td&gt;Weather on the top bar of one of the screens, News and Weather application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;L&lt;/td&gt;
&lt;td&gt;Wordpress&lt;/td&gt;
&lt;td&gt;Wordpress&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
&lt;b&gt;The Purchase&lt;/b&gt;&lt;br /&gt;
I knew I wanted to buy the Nexus One the minute it was presented to the world :) There were however a lot of factors to take into account, the applications that I had and what their replacements will be (see table above), whether it would work reliably with AT&amp;amp;T's network or whether I would have to switch to T-Mobile etc.&lt;br /&gt;
&lt;br /&gt;
I have been following closely web posts regarding experiences with the Nexus One and I must admit, it was one of the main factors that helped me make the decision to switch. The icing on the cake was Matt Cutts's post regarding the same issue: &lt;a href="http://www.mattcutts.com/blog/switch-iphone-to-android/"&gt;Leaving the iPhone&lt;/a&gt;. I decided that I would get the phone and if it works satisfactory on AT&amp;amp;T I will stay with them, otherwise I will switch to T-Mobile.
&lt;br /&gt;
&lt;br /&gt;
I discussed the issue with the boss (my wife who else :)) and the purchase was approved. As a matter of fact she was disappointed when I told her that I am going to order it because she had plans to buy it for me for my birthday in April. My eagerness to get the new phone spoiled the surprise but we both agreed that I got my birthday present two months in advance :)
&lt;br /&gt;
&lt;br /&gt;
The purchase was really trouble free. I also purchased the dock and the really nice surprise is that Google offers free overnight FedEx to your location. It came in handy since I really wanted the phone there and then!
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;First experience
&lt;/b&gt;&lt;br /&gt;
The phone arrived while I was at work. When I came back home, two really nice boxes were waiting for me. As you can see the packaging is really nice and the Google colors appear subtly on it.&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-AV6fLWx5IC8/Tr1YLey6PAI/AAAAAAAAFng/-nFfyRLTh-4/s1600/IMG_12651.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-AV6fLWx5IC8/Tr1YLey6PAI/AAAAAAAAFng/-nFfyRLTh-4/s320/IMG_12651.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One and Nexus One Dock packaging&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ESakS17YTrw/Tr1YLu9_QtI/AAAAAAAAFno/hZwrxqaFDSE/s1600/IMG_12661.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-ESakS17YTrw/Tr1YLu9_QtI/AAAAAAAAFno/hZwrxqaFDSE/s320/IMG_12661.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One package - Subtle Google color detail&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
The packaging is simply awesome. Great ergonomics which easily match the ones of the iPhone. The Nexus One was wrapped in a plastic protective wrap, while in the package there was a protective sleeve, the USB cable, the headset and the charger. The packaging for the Nexus One Dock was equally good and it contained the dock and its charger.&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-kCCF86qL6YA/Tr1YMKo3C0I/AAAAAAAAFnw/X-q4OjRatzQ/s1600/IMG_12671.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-kCCF86qL6YA/Tr1YMKo3C0I/AAAAAAAAFnw/X-q4OjRatzQ/s320/IMG_12671.jpg" width="240" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One - Straight out of the box&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-DJW9LgU0518/Tr1YM0Ic0PI/AAAAAAAAFn4/ET1SayoagqI/s1600/IMG_12691.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-DJW9LgU0518/Tr1YM0Ic0PI/AAAAAAAAFn4/ET1SayoagqI/s320/IMG_12691.jpg" width="240" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One - Protective sleeve&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-BPO1HQAPqF0/Tr1YNTN9rWI/AAAAAAAAFoA/NHrXJypqRZM/s1600/IMG_12731.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-BPO1HQAPqF0/Tr1YNTN9rWI/AAAAAAAAFoA/NHrXJypqRZM/s320/IMG_12731.jpg" width="240" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One - Warranty Information&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-uLUHErNTCYg/Tr1YNy8RffI/AAAAAAAAFoI/wV2R6M9Wrw8/s1600/IMG_12741.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-uLUHErNTCYg/Tr1YNy8RffI/AAAAAAAAFoI/wV2R6M9Wrw8/s320/IMG_12741.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One - Charger, USB cable, Headsets&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-idiJ7TSgYXo/Tr1YOTxGYbI/AAAAAAAAFoQ/hc_970sX5Ws/s1600/IMG_12761.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-idiJ7TSgYXo/Tr1YOTxGYbI/AAAAAAAAFoQ/hc_970sX5Ws/s320/IMG_12761.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One Dock&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
Abiding to the instructions, I opened the phone, inserted the battery &amp;nbsp;and plugged it in so that I will get a full charge prior to doing anything else.&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-mgLxlTmlOvk/Tr1YOj8yO8I/AAAAAAAAFoY/X6w-Xg9kOls/s1600/IMG_12781.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-mgLxlTmlOvk/Tr1YOj8yO8I/AAAAAAAAFoY/X6w-Xg9kOls/s320/IMG_12781.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One - Open with battery&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
As soon as I put the battery in, the phone booted up. Really slick graphics!&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-JnPiJM0rz08/Tr1YPNJhL6I/AAAAAAAAFog/MyYD-432mHQ/s1600/IMG_12821.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-JnPiJM0rz08/Tr1YPNJhL6I/AAAAAAAAFog/MyYD-432mHQ/s320/IMG_12821.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One - Booting up 1&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-Oecw-l55TDg/Tr1YPZdp4YI/AAAAAAAAFoo/uDe8AHaqagQ/s1600/IMG_12831.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-Oecw-l55TDg/Tr1YPZdp4YI/AAAAAAAAFoo/uDe8AHaqagQ/s320/IMG_12831.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One - Booting up 2&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-u0tY_7a0rBI/Tr1YP4CzJII/AAAAAAAAFow/Ah8bVZvMoFE/s1600/IMG_12841.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-u0tY_7a0rBI/Tr1YP4CzJII/AAAAAAAAFow/Ah8bVZvMoFE/s320/IMG_12841.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Nexus One - Booting up 3&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
While the Nexus One was charging, I inspected my iPhone once more and synced it to my computer so that I do not lose any data. Once the phone was fully charged, I removed the battery and inserted the AT&amp;amp;T card in it. The network was identified immediately and I was able to log in using my Google Apps account! :) After a few steps of setting up the phone was ready for use.&lt;br /&gt;
&lt;br /&gt;
I plugged in the dock and set the phone up on it so that it charges prior to turning in. A nice surprise was the again subtle green digital clock that appeared on the phone while it is docked. I always wanted to have a nice clock on my bed stand - now I got it :)
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The day after
&lt;/b&gt;&lt;br /&gt;
I started the day with the attitude of '&lt;em&gt;Forget the iPhone and start anew&lt;/em&gt;'. It was difficult, I must admit, but I think I managed quite well. The more I was using the Nexus One the more I liked it. I installed all the applications that I wanted (see table above) and set up the screens with the relevant application icons, trying to resemble what I had on the iPhone so that I won't spend much time looking for application icons.&lt;br /&gt;
&lt;br /&gt;
I set up Google Voice and that was one thing that really impressed me. The task was completed in a matter of minutes and now everyone will receive calls from my Google Voice number and not from my AT&amp;amp;T number. I no longer have to go to GV Mobile or the web based application to search for a contact and then call using Google Voice. Big plus here for Nexus One over the iPhone.
&lt;br /&gt;
&lt;br /&gt;
Another pleasant surprise came a bit later when my wife and I had to goto a car dealer to view some cars (minivan here we come). I had the instructions and I had added the address of the car dealer in the event in Google Calendar. Usually I would use Google Maps and calculate the mileage that I travel with what Google Maps says and before I reach the next milestone I look at the map again. This time I saw a 'Navigate' link in the menu that appeared and for the fun of it I chose it. I was in turn greeted with a female voice telling me exactly where to go. As I am really notorious for getting lost, the female voice proceeded to tell me to make a U-turn to get back on track :) Really slick and accurate! Big plus again for the Nexus One over the iPhone.
&lt;br /&gt;
&lt;br /&gt;
The notifications for the emails (I set up all my email accounts) are equally good for both phones. The Nexus One has a very slight advantage here in my opinion, since the notification area pulls up all the notifications that you have - from installed applications, text messages, missed phone calls, new emails etc. On the iPhone you get notifications on a per application basis so you need to be on the screen that lists the application that you received a notification for. Plus again for the Nexus One over the iPhone.
&lt;br /&gt;
&lt;br /&gt;
Website rendering is where the Nexus One gets another plus. I think it is hardware since I am using the same AT&amp;amp;T network but the sites load noticeably faster on the Nexus One over the iPhone. This is normal browsing in the house so the location is pretty much the same. Big plus again for the Nexus One over the iPhone.
&lt;br /&gt;
&lt;br /&gt;
Email management is where the iPhone is better. If I have say 4 emails to read and I click on one of them, I have to click the menu and then the 'Newer' button to get to the next email that I have not read. On the iPhone you have an up and a down arrow that allows you to navigate a lot easier. Also on the iPhone there is a logical hierarchy of accounts and folders, so you go back to change to a different account. Although this is a lot more work than it should, it seems a lot more logical than the approach the Nexus One has. With the Nexus One all you have to do is click the menu button and click Accounts to quickly access another account. It is a lot less clicks and I guess it would have made perfect sense should I had just come from a flip phone and never knew the iPhone. Still personal preference goes with the iPhone implementation, despite the fact that I am getting used to the new way of doing things :) Big plus for the iPhone over the Nexus One.
&lt;br /&gt;
&lt;br /&gt;
Multitasking - multiple application notifications. This one has been the most discussed thing on the Internet regarding the iPhone (and now the iPad). You cannot run multiple applications at the same time. I just received a notification that I have a new email and someone replied to one of my tweets. The Nexus One notification bar showed both notifications and I read both messages in no time. On the iPhone though I had to keep the TweetDeck application on so that I can get the notification OR the Mail application on so that I can get the email. Huge plus for the Nexus One over the iPhone.
&lt;br /&gt;
&lt;br /&gt;
There are other areas that I could discuss here but they are mostly focused on personal preferences on how things are done or should be done.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion
&lt;/b&gt;&lt;br /&gt;
Overall I am really glad that I made the switch. The screen and camera are amazing, the phone is really responsive and apart from a couple of times that I didn't know how to do something and I had to Google it, I am using it as if I had it for a long time. &amp;nbsp;I have no restrictions, I don't have to jailbreak the device so that I can get some applications that Apple deemed that they "ruin the user experience" (according to &lt;a href="http://www.apple.com/hotnews/apple-answers-fcc-questions/"&gt;their reply to the FCC&lt;/a&gt; regarding Google Voice), my data is synchronized with the cloud and &lt;a href="http://www.dataliberation.org/"&gt;I can get it out of there at will&lt;/a&gt;. I can even develop my own application and install it if I wish to. This is something that the iPhone does not provide and notable is the fact that I had to retype all my store cards that I used Cardscan for in the Key Card scanner and there is no way for me to get the data that FuelGauge has stored in it and potentially transfer it to aCar.&lt;br /&gt;
&lt;br /&gt;
I would say that the iPhone would suit someone that is not that tech savvy and is not impressed by the technical abilities of the phone, rather is focused on the amount of applications that exist for that phone (iPhone is superior there). The Nexus One though raised the bar way high and it will take a long time for the iPhone to even come close to it. Once the Apple introduces the ability to allow multiple applications to run at the same time, provide the liberty to get your data out of it if you wish to, stop trying to police people by restricting applications, &amp;nbsp;then the gap would have been bridged but until then... in my humble opinion the Nexus One is king!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-7938892185280354957?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/MgBz6FnRfCo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/7938892185280354957/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/02/from-iphone-to-nexus-one-review.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/7938892185280354957?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/7938892185280354957?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/MgBz6FnRfCo/from-iphone-to-nexus-one-review.html" title="From iPhone to Nexus One [Review]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-AV6fLWx5IC8/Tr1YLey6PAI/AAAAAAAAFng/-nFfyRLTh-4/s72-c/IMG_12651.jpg" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/02/from-iphone-to-nexus-one-review.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUFSX85fSp7ImA9WhRSEE4.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-7971807536738654886</id><published>2010-02-18T08:50:00.000-05:00</published><updated>2011-11-11T13:46:58.125-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T13:46:58.125-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Wordpress" /><category scheme="http://www.blogger.com/atom/ns#" term="Communications" /><category scheme="http://www.blogger.com/atom/ns#" term="Rant" /><title>Spam - oh how I hate it [Rant]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-zrwsxlIKT58/Tr1tmXDVJWI/AAAAAAAAFus/GXt6_IYLmuU/s1600/spam-filtering-software.gif" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-zrwsxlIKT58/Tr1tmXDVJWI/AAAAAAAAFus/GXt6_IYLmuU/s320/spam-filtering-software.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
Everyone (by now) knows what spam is and by far it is one of the most hated 'things' of this world. Although it comes in many forms, people tend to be a lot more sensitive to spam when it relates to their email than their snail mail or any other form of it.
&lt;br /&gt;
&lt;br /&gt;
Junk is junk no matter how you want to see it. If I have not asked for something, then you are spamming me. If I politely say no the first time - don't send me any of the junk you are selling -&lt;strong&gt; I do not want it&lt;/strong&gt;! Simple as that.
&lt;br /&gt;
&lt;br /&gt;
If materials (email form, mail form etc.) ignore the above then they are categorized as spam.
&lt;br /&gt;
&lt;br /&gt;
I have mentioned in a &lt;a href="http://www.niden.net/2009/11/google-apps/"&gt;previous post&lt;/a&gt; that I have moved my domain to Google Apps and of course with it my email. This move allowed me to be virtually spam free, since Google's spam filter is the best one there is. The random email that I will get maybe once a month is not a problem since I can report it as spam and never see it again.
&lt;br /&gt;
&lt;br /&gt;
With the evolution of blogs and the need to allow people to comment on one's blog entries, spammers found new ground to spread their disease. The blog's comment box became a really good target, thus automated bots have been created to post junk in a blog's comment box. &amp;nbsp;These entries make no sense, they contain links mostly to pharmaceutical products and sometimes are really funny. Their purpose though is to establish links pointing to a particular site (or sites) so that search engines (mainly Google) would be 'fooled' to bring the target site higher in the search result listing.
&lt;br /&gt;
&lt;br /&gt;
Features like &lt;strong&gt;rel='nofollow'&lt;/strong&gt; on the href declaration of every link in the comments can help with this situation. This directive instructs the search engine spider not to follow the link in the new site, thus negating the intended spam's behavior.
&lt;br /&gt;
&lt;br /&gt;
The Akismet plugin for Wordpress blogs (such as this one) allows for a more automated protection against spam. Akismet captures spam comments and keeps them in a queue where the admin of the blog (moi!) can go later on and check if there are any false positives caught in the spam queue. I have to give kudos to everyone involved in creating the plugin to Akismet and the service itself. This contribution to bloggers around the world is invaluable.
&lt;br /&gt;
&lt;br /&gt;
The cure to spam? Delete it and/or ignore it. The spammers of this world thrive if they see a return on the investment. Note that there are two parties in the equation. The first party is the spammer, the person that actually does the deed - runs the mail server, sends the emails, creates the spam comments etc. The second guilty party is the actual employer of that spammer. The XYZ corporation that wants to sell pharmaceutical products or printer supplies etc. If the latter gets a zero return on their investment, then they will stop paying the spammers to send junk to us. &amp;nbsp;Since their return on investment is minimal (I read somewhere that one needs 1/100,000 return to break even) they will keep on hiring spammers to send more and more spam.
&lt;br /&gt;
&lt;br /&gt;
What do you need to do? Just ignore spam. Report it, delete it, ignore it, protect against it. Don't buy anything from spam related messages in an effort to reduce and hopefully negate the return on investment of the spammer's employer. &amp;nbsp;This will effectively benefit not only yourself but everyone else that uses the Internet.
&lt;br /&gt;
&lt;br /&gt;
I will leave you with two spam messages caught in Akismet a week ago which I find really funny:
&lt;br /&gt;
&lt;br /&gt;
For my post about &lt;a href="http://www.niden.net/2010/01/how-to-create-a-ssl-certificate-linux/"&gt;SSL Certificates&lt;/a&gt;:
&lt;br /&gt;
&lt;blockquote&gt;
Normally, university teachers are willing to examine the business term paper writing technique of their students, nevertheless &lt;strong&gt;not all students can to write correctly because of a job&lt;/strong&gt; or other issues. Therefore, a essay writing service should aid to compose the term paper thesis professionally.&lt;/blockquote&gt;
For my post about &lt;a href="http://www.niden.net/2010/02/design-patterns-factory-series-how-to/"&gt;PHP and the Factory Pattern&lt;/a&gt;:
&lt;br /&gt;
&lt;blockquote&gt;
I am bare impressed with the article I have just read. I wish the writer of http://www.niden.net can continue to provide so much useful information and unforgettable experience to http://www.niden.net readers. &lt;strong&gt;There is not much to say except the following universal truth: Everyone had an uncle who tried to steal their nose.&lt;/strong&gt; I will be back.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-7971807536738654886?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/YFIMfdg0Pis" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/7971807536738654886/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/02/spam-oh-how-i-hate-it-rant.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/7971807536738654886?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/7971807536738654886?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/YFIMfdg0Pis/spam-oh-how-i-hate-it-rant.html" title="Spam - oh how I hate it [Rant]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-zrwsxlIKT58/Tr1tmXDVJWI/AAAAAAAAFus/GXt6_IYLmuU/s72-c/spam-filtering-software.gif" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/02/spam-oh-how-i-hate-it-rant.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUACQH06eSp7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-6635103987120307385</id><published>2010-02-02T08:42:00.000-05:00</published><updated>2011-11-11T15:36:01.311-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T15:36:01.311-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Zend Framework" /><category scheme="http://www.blogger.com/atom/ns#" term="MySQL" /><category scheme="http://www.blogger.com/atom/ns#" term="Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="Design Patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="Series" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><title>Design Patterns – Factory [Series][How-To]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-epOqhyQH4D4/Tr2HKw-kMoI/AAAAAAAAFw8/O3e9QdI7v64/s1600/dp_misc.gif" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="291" src="http://3.bp.blogspot.com/-epOqhyQH4D4/Tr2HKw-kMoI/AAAAAAAAFw8/O3e9QdI7v64/s320/dp_misc.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
A note about these series. It appears that &lt;a href="http://giorgiosironi.blogspot.com/"&gt;Giorgio Sironi&lt;/a&gt; and I had the same idea regarding Design Patterns and blogging about them. He covers the &lt;a href="http://giorgiosironi.blogspot.com/2010/01/practical-php-patterns-factory-method.html"&gt;Factory&lt;/a&gt; design pattern thoroughly in his blog post, which is recommended reading.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Problem
&lt;/b&gt;&lt;br /&gt;
I started off my IT career as a network administrator. This was back in the good old Novell 3.11 days. After that it was Novell 4.0, Microsoft Servers etc. Following that I got more and more involved with Visual Basic and when Microsoft decided to move everyone to .NET I chose not to follow and ended up coding in PHP.&lt;br /&gt;
&lt;br /&gt;
Since my programming knowledge came from within (studying, reading articles, trial and error), the problems that I was facing on a daily basis are the same as almost every developer faces. One particularly challenging problem that I had in the VB days as well as the PHP days was repetition of code and how to eliminate it.
&lt;br /&gt;
&lt;br /&gt;
When I started programming for the &lt;a href="http://ffff.niden.net/"&gt;Ferrari Fans Fun Forecast&lt;/a&gt; site I was running the site using my apartment's ADSL line. In the beginning there were only 20 users or so, therefore that setup was fine. The scripts were VBScript against a local instance of Microsoft SQL Server. Later on though, I switched to PHP while keeping Microsoft SQL Server.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Initial implementation
&lt;/b&gt;&lt;br /&gt;
I knew that I would have to change my scripts later on to work against MySQL since I was to change the hosting of the site. Through laziness or poor design (you can pick either or both :)) I chose to create a class for Microsoft SQL and later on I would just change it to the MySQL. It seemed the easiest thing to do at the time.&lt;br /&gt;
&lt;br /&gt;
So my class was something like:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;class DbMSSQL
{
    private $_conn = null;

    public function connect()
    {
         // Connect
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&amp;gt;_conn = mssql_connect($host, $user, $password);
        if (!$this-&amp;gt;_conn) {
            throw new Exception('Cannot connect to the database.');
        }
    }

    public function disconnect()
    {
         // Disconnect
        mssql_close($this-&amp;gt;_conn);
    }

    public function selectdb()
    {
         // Select the db
        $db = mssql_select_db($database, $this-&amp;gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database');
        }
    }

    public function query($sql)
    {
     // Query the db
        $_result = mssql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . $sql);
        }

        $data = array();

        while ($row = mssql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mssql_free_result($_result);

        return $data;
    }
}
&lt;/pre&gt;
Everything worked fine so I did not worry about a thing. A few months later though I was forced to move the database (as I expected) to MySQL. I could not move everything in one go so I had to move some of the tables initially and a week later everything else.
&lt;br /&gt;
&lt;br /&gt;
To tackle this requirement I created a second class to handle operations against MySQL. The class that I ended up with was:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;class DbMySQL
{
    private $_conn = null;

    public function connect()
    {
         // Connect
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&amp;gt;_conn = mysql_connect($host, $user, $password);
        if (!$this-&amp;gt;_conn) {
            throw new Exception('Cannot connect to the database :' . mysql_error());
        }
    }

    public function disconnect()
    {
         // Disconnect
        mysql_close($this-&amp;gt;_conn);
    }

    public function selectdb()
    {
         // Select the db
        $db = mysql_select_db($database, $this-&amp;gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database : ' . mysql_error());
        }
    }

    public function query($sql)
    {
     // Query the db
        $_result = mysql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . mysql_error() . "\n" . $sql);
        }

        $data = array();

        while ($row = mysql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mysql_free_result($_result);

        return $data;
    }
}
&lt;/pre&gt;
You can easily see the problem here. There is a lot of repetition in the code, not so much as the actual method properties but the methods themselves. Both classes have connect(), disconnect(), selectdb() and query() as methods. In reality the code changes only slightly since the call for an operation against Microsoft SQL Server is &lt;strong&gt;mssql_*&lt;/strong&gt; while for MySQL is &lt;strong&gt;mysql_*&lt;/strong&gt;. During the transition week I was in programming hell. At some point I mixed the class names, I was trying to read and update the wrong server etc. (see &lt;a href="http://codeutopia.net/"&gt;Jani Hartikainen&lt;/a&gt;'s post about &lt;a href="http://codeutopia.net/blog/2010/01/28/6-programming-project-mistakes-you-should-avoid/"&gt;6 programming project mistakes you should avoid&lt;/a&gt; - I did all that!).
&lt;br /&gt;
&lt;br /&gt;
That week though taught me that I need to pay more attention in designing rather than going full speed ahead with programming and later on paying the consequences.
&lt;br /&gt;
&lt;br /&gt;
After thorough research, I discovered a&amp;nbsp;library that would support both platforms. The library that I found was &lt;a href="http://adodb.sourceforge.net/"&gt;ADOdb&lt;/a&gt; which is a perfect example of the Factory Pattern. I used that library later on for a different project, but just looking at the code and understanding the flow of operations as well as the implementation of the pattern itself was invaluable to me.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Interfaces
&lt;/b&gt;&lt;br /&gt;
First of all I need to explain what an interface is and why we need them. According to &lt;a href="http://php.net/manual/en/language.oop5.interfaces.php"&gt;PHP.net&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;
Object interfaces allow you to create code which specifies which methods a class must implement, without having to define how these methods are handled.&lt;/blockquote&gt;
So imagine an interface something like a graft, a blueprint on what I need to construct. The Interface will have the common methods and properties that I need to implement.
&lt;br /&gt;
&lt;br /&gt;
When dealing with database connections to two different database servers (Microsoft SQL Server and MySQL), I can clearly define a few methods that will follow CRUD (Create, Read, Update, Delete). Those are:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Connect to the database server&lt;/li&gt;
&lt;li&gt;Select database&lt;/li&gt;
&lt;li&gt;Insert record&lt;/li&gt;
&lt;li&gt;Delete record&lt;/li&gt;
&lt;li&gt;Update record&lt;/li&gt;
&lt;li&gt;Select record(s)&lt;/li&gt;
&lt;li&gt;Close connection to the database server&lt;/li&gt;
&lt;/ol&gt;
My interface would therefore be:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;interface iDatabase
{
    public function connect();
    public function disconnect();
    public function selectdb();
    public function query($sql);
}
&lt;/pre&gt;
&lt;b&gt;Design Patterns - Factory&lt;/b&gt;&lt;br /&gt;
A class implementing the Factory Pattern is like a car&amp;nbsp;manufacturing&amp;nbsp;plant producing three different cars on the same assembly line. All cars have common characteristics like 4 wheels, 4 doors (well most of them), a steering wheel, a dashboard etc. and all of them perform certain operations i.e. drive, reverse etc.&lt;br /&gt;
&lt;br /&gt;
In my problem earlier I could have used the Factory Pattern to create one class that would have implemented my blueprint, the interface which defines the CRUD operations that I need. So based on the above, the implementation will result in three classes.
&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;MSSQL class - stored in the file Db_mssql.php
&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;class Db_mssql implements iDatabase
{
    private $_conn = null;

    public function connect()
    {
         // Connect
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&amp;gt;_conn = mssql_connect($host, $user, $password);
        if (!$this-&amp;gt;_conn) {
            throw new Exception('Cannot connect to the database.');
        }
    }

    public function disconnect()
    {
         // Disconnect
        mssql_close($this-&amp;gt;_conn);
    }

    public function selectdb()
    {
         // Select the db
        $db = mssql_select_db($database, $this-&amp;gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database');
        }
    }

    public function query($sql)
    {
     // Query the db
        $_result = mssql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . $sql);
        }

        $data = array();

        while ($row = mssql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mssql_free_result($_result);

        return $data;
    }
}
&lt;/pre&gt;
&lt;i&gt;MySQL class - stored in the file Db_mysql.php&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;class Db_mysql implements iDatabase
{
    private $_conn = null;

    public function connect()
    {
         // Connect
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&amp;gt;_conn = mysql_connect($host, $user, $password);
        if (!$this-&amp;gt;_conn) {
            throw new Exception('Cannot connect to the database :' . mysql_error());
        }
    }

    public function disconnect()
    {
         // Disconnect
        mysql_close($this-&amp;gt;_conn);
    }

    public function selectdb()
    {
         // Select the db
        $db = mysql_select_db($database, $this-&amp;gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database : ' . mysql_error());
        }
    }

    public function query($sql)
    {
     // Query the db
        $_result = mysql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . mysql_error() . "\n" . $sql);
        }

        $data = array();

        while ($row = mysql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mysql_free_result($_result);

        return $data;
    }
}
&lt;/pre&gt;
Notice that both these classes are almost identical to the initial implementation shown earlier in this post. The only difference is that they are both implementing the iDatabase interface.
&lt;br /&gt;
&lt;br /&gt;
So what is different now? The class that implements the Factory Pattern.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;class Db
{
    public static function factory($type)
    {
        $fileName = 'Db_' . strtolower($type) . '.php';
        if (!file_exists($fileName)) {
            throw new Exception('File not found : ' . $fileName);
        }

        $className = 'Db_' . strtolower($type);

        return new $className;
    }
}&lt;/pre&gt;
&lt;br /&gt;
What this class does now is it allows me to load the relevant database connection class on the fly. If I want a Microsoft SQL connection I would call:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;    $mssql = Db::factory('mssql');&lt;/pre&gt;
&lt;br /&gt;
while for MySQL the command becomes:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;    $mysql = Db::factory('mysql');&lt;/pre&gt;
&lt;br /&gt;
Again since both underlying classes implement the iDatabase interface, I know exactly what to expect as far as methods and functionality is concerned from each class.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion
&lt;/b&gt;&lt;br /&gt;
The Factory Design Pattern is one of the most powerful design patterns. It provides 'decoupling' i.e. breaks the inherited dependency of a class and its subclasses. It also&amp;nbsp;allows for great flexibility while keeping the same interface for your clients.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://framework.zend.com/"&gt;Zend Framework&lt;/a&gt; uses the Factory Pattern in &lt;a href="http://framework.zend.com/manual/en/zend.db.adapter.html"&gt;Zend_Db&lt;/a&gt;. Specifically the example on the site shows:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;// We don't need the following statement because the
// Zend_Db_Adapter_Pdo_Mysql file will be loaded for us by
// the Zend_Db factory method.

// require_once 'Zend/Db/Adapter/Pdo/Mysql.php';

// Automatically load class Zend_Db_Adapter_Pdo_Mysql
// and create an instance of it.
$db = Zend_Db::factory('Pdo_Mysql', array(
          'host'     =&amp;gt; '127.0.0.1',
          'username' =&amp;gt; 'webuser',
          'password' =&amp;gt; 'xxxxxxxx',
          'dbname'   =&amp;gt; 'test'
      ));&lt;/pre&gt;
&lt;br /&gt;
The &lt;a href="http://framework.zend.com/manual/en/zend.db.adapter.html"&gt;Zend_Db&lt;/a&gt; factory accepts the name of the adapter used for the database connection as the first parameter while the second parameter is an array with connection specific information. With the use of the Factory Pattern, &lt;a href="http://framework.zend.com/manual/en/zend.db.adapter.html"&gt;Zend_Db&lt;/a&gt; exposes a common interface which allows programmers to connect to a number of databases using the same methods. Should in the future the application needs to access a different database, the impact to the developer is minimal - in most cases a change to the adapter name (first parameter of the factory class) is all it takes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-6635103987120307385?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/CFdnTN2Qm8A" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/6635103987120307385/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/02/design-patterns-factory-serieshow-to.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/6635103987120307385?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/6635103987120307385?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/CFdnTN2Qm8A/design-patterns-factory-serieshow-to.html" title="Design Patterns – Factory [Series][How-To]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-epOqhyQH4D4/Tr2HKw-kMoI/AAAAAAAAFw8/O3e9QdI7v64/s72-c/dp_misc.gif" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/02/design-patterns-factory-serieshow-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUADRn4_eCp7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-8160675192734235281</id><published>2010-01-22T08:36:00.000-05:00</published><updated>2011-11-11T15:36:17.040-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T15:36:17.040-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Zend Framework" /><category scheme="http://www.blogger.com/atom/ns#" term="MySQL" /><category scheme="http://www.blogger.com/atom/ns#" term="Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="Design Patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="Series" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><title>Design Patterns - Singleton [Series][How-To]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-epOqhyQH4D4/Tr2HKw-kMoI/AAAAAAAAFw8/O3e9QdI7v64/s1600/dp_misc.gif" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="291" src="http://3.bp.blogspot.com/-epOqhyQH4D4/Tr2HKw-kMoI/AAAAAAAAFw8/O3e9QdI7v64/s320/dp_misc.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
A note about these series. It appears that &lt;a href="http://giorgiosironi.blogspot.com/"&gt;Giorgio Sironi&lt;/a&gt; and I had the same idea regarding Design Patterns and blogging about them. He covers the &lt;a href="http://giorgiosironi.blogspot.com/2010/01/practical-php-patterns-singleton.html"&gt;Singleton&lt;/a&gt; design pattern thoroughly in his blog post, which is recommended reading.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Problem
&lt;/b&gt;&lt;br /&gt;
When I started programming in PHP I was faced with creating a simple database driven web page for a &lt;a href="http://ffff.niden.net/"&gt;Ferrari Fans Fun club&lt;/a&gt;. The page had 5 different sections that each accessed the database to retrieve data. Each section was included in more than one page and only the menu, header and footer were common in all pages.&lt;br /&gt;
&lt;br /&gt;
My first design and implementation was horrible. I still have the files and for the purposes of this blog post I went back and checked on them and I can safely say I am ashamed of that code. But then again we all start from somewhere so that was my start and more importantly I do not program like that any more. The picture below shows how the page was constructed:
&lt;br /&gt;
&lt;br /&gt;
&lt;table border="0" style="border: 1px solid #4B0082; width: 100%;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan="3" style="border: 1px solid #4B0082; font-weight: bold; height: 50px; text-align: center;"&gt;Header&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="border: 1px solid #4B0082; font-weight: bold; height: 100px; text-align: center; width: 20%;"&gt;Menu&lt;/td&gt;
&lt;td style="border: 1px solid #4B0082; font-weight: bold; height: 100px; text-align: center; width: 60%;"&gt;Content&lt;/td&gt;
&lt;td style="border: 1px solid #4B0082; font-weight: bold; height: 100px; text-align: center; width: 20%;"&gt;Additional information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="3" style="border: 1px solid #4B0082; font-weight: bold; height: 50px; text-align: center;"&gt;Footer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
Each of the sections was a different php script (header.php, menu.php, content.php, footer.php, info.php) and in order to retrieve information from the database for each section I had the following snippet at the top of each script:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;$dbName = 'FFFF';
$dbUser = 'ffff_user';
$dbPass = 'mypassword';
$dbHost = 'localhost';

$conn = mysql_connect($dbHost, $dbUser, $dbPass);
if (!$conn) {
    die(('Cannot connect to the database :' . mysql_error());
}

$db = mysql_select_db($dbName, $conn);
if (!$db) {
    die ('Cannot select the database : ' . mysql_error());
}&lt;/pre&gt;
&lt;br /&gt;
Some might comment on my error handling or the naming of the variables. That is not the problem. The problem is that the snippet of code above was used in &lt;strong&gt;every script file&lt;/strong&gt; (all 5 of them). As a result every page load was hitting the database 5 times. Although the intended user base was no more than 100 people, due to this design flaw I had the equivalent of 500 users.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The first step - Primitive refactoring
&lt;/b&gt;&lt;br /&gt;
You might argue that the two files (header, menu) can easily be combined into one (and the same with additional information and footer) and that will save me 3 connections. The layout does not change but now each of the shaded areas represent one script:&lt;br /&gt;
&lt;br /&gt;
&lt;table border="0" style="border: 1px solid #4B0082; width: 100%;"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan="3" style="background: #DD0000; border: 1px solid #4B0082; font-weight: bold; height: 50px; text-align: center;"&gt;Header&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="background: #DD0000; border: 1px solid #4B0082; font-weight: bold; height: 100px; text-align: center; width: 20%;"&gt;Menu&lt;/td&gt;
&lt;td style="border: 1px solid #4B0082; font-weight: bold; height: 100px; text-align: center; width: 60%;"&gt;Content&lt;/td&gt;
&lt;td style="background: #00DD00; border: 1px solid #4B0082; font-weight: bold; height: 100px; text-align: center; width: 20%;"&gt;Additional information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="3" style="background: #00DD00; border: 1px solid #4B0082; font-weight: bold; height: 50px; text-align: center;"&gt;Footer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
Although this is a good start it is not the solution to the problem. I have effectively reduced the number of hits to 3 per visitor (300 vs 500 before). The goal is to have one connection per visitor.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;One step further - A global variable
&lt;/b&gt;&lt;br /&gt;
I need to create the database connection, store it in a global variable, and then let the rest of the scripts access that variable - and subsequently the database connection - when needed. The pseudo code is as follows:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Load script header.php&lt;/li&gt;
&lt;li&gt;Get the database credentials&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create a database connection&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Select the database&lt;/li&gt;
&lt;li&gt;Display the data&lt;/li&gt;
&lt;li&gt;Load script content.php&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get the database connection&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Display the data&lt;/li&gt;
&lt;li&gt;Load script footer.php&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get the database connection&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Display the data&lt;/li&gt;
&lt;/ol&gt;
I need to ensure that my database connection is initiated at the beginning of every page. The script header.php is the most obvious place:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;$dbName = 'FFFF';
$dbUser = 'ffff_user';
$dbPass = 'mypassword';
$dbHost = 'localhost';

$DBconn = mysql_connect($dbHost, $dbUser, $dbPass);
if (!$DBconn) {
    die(('Cannot connect to the database :' . mysql_error());
}

$db = mysql_select_db($dbName, $DBconn);
if (!$db) {
    die ('Cannot select the database : ' . mysql_error());
}&lt;/pre&gt;
&lt;br /&gt;
In every script thereafter I need to reference the global variable and I can then use it in that script:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php"&gt;global $DBconn;&lt;/pre&gt;
&lt;br /&gt;
Although this is an "acceptable" way of programming, maintaining all the global variables can easily be a nightmare for
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;maintenance&lt;/li&gt;
&lt;li&gt;testing&lt;/li&gt;
&lt;li&gt;quality control&lt;/li&gt;
&lt;li&gt;any part of the code in any script that references this global variable can effectively change that variable&lt;/li&gt;
&lt;li&gt;that the code will look "ugly" (hey I am proud of the code that I write :))&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Design Patterns - Singleton&lt;/b&gt;&lt;br /&gt;
A better approach to solve this problem is to use a design pattern. In this case I will use the Singleton Pattern.&lt;br /&gt;
&lt;br /&gt;
The Singleton pattern is applied to a class which when called will create a database connection if the connection does not exist or pass the connection back to the caller if it has already been instantiated. This way I really do not care where the database credentials will be added and when the connection will be instantiated. The first time that I am calling the class that implements the Singleton pattern will connect to the database and have the connection stored ready to be used. The pseudo code is as follows:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Load script header.php&lt;/li&gt;
&lt;li&gt;Get the database credentials&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create a database connection&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Select the database&lt;/li&gt;
&lt;li&gt;Display the data&lt;/li&gt;
&lt;li&gt;Load script content.php&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get the database connection&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Display the data&lt;/li&gt;
&lt;li&gt;Load script footer.php&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get the database connection&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Display the data&lt;/li&gt;
&lt;/ol&gt;
The class that I created is as follows:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;class Db
{
    private static $_db   = null;
    private static $_conn = null;

    private function __construct()
    {
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&amp;gt;_conn = mysql_connect($host, $user, $password);
        if (!$this-&amp;gt;_conn) {
            throw new Exception('Cannot connect to the database :' . mysql_error());
        }

        $db = mysql_select_db($database, $this-&amp;gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database : ' . mysql_error());
        }
    }

    private function __destruct()
    {
        mysql_close($this-&amp;gt;_conn);
    }

    // The singleton method
    public static function getInstance()
    {
        if (null === self::$db) {
            self::$_db = new Db($options);
        }

        return self::$_db;
    }

    public function query($sql)
    {
        $_result = mysql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . mysql_error() . "\n" . $sql);
        }

        $data = array();

        while ($row = mysql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mysql_free_result($_result);

        return $data;
    }
}
&lt;/pre&gt;
&lt;br /&gt;
With this class available I really do not care if my database connection code is at the beginning of my scripts or not. Using this class allows me to create the database connection (if it is not established) and persist/reuse it further down the script execution.
&lt;br /&gt;
&lt;br /&gt;
The code for my header and menu (see graphic above) becomes:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre lang="php" line="1"&gt;    $sql = 'SELECT menu_id, menu_name FROM tbl_menu';
    $menu = Db::getInstance()-&amp;gt;query($sql);&lt;/pre&gt;
&lt;br /&gt;
while the one for the rest of the site is exactly identical sans the query to be executed. The problem is solved (I now have one connection per visitor) and the code seems a lot tidier.
&lt;br /&gt;
&lt;br /&gt;
Note that the connection parameters are in a separate file which is accessed during the __construct() method of the class. You can use anything you want to supply these parameters in your class.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion
&lt;/b&gt;&lt;br /&gt;
The Singleton Design Pattern is a blessing in disguise. If the ground work has not been done (i.e. create tests for your code and thoroughly document it) then it is difficult for a new developer coming into a project to understand what is going on, especially when the new developer needs to make alterations and run newly created tests.&lt;br /&gt;
&lt;br /&gt;
A word of caution: If you choose to use this pattern in your application, make sure that everything you do is thoroughly documented and tested. This will make your life a lot easier in the long run and will aid in maintenance.
&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Update&lt;/i&gt;: Thanks to &lt;a href="http://codeutopia.net/" rel="external nofollow"&gt;Jani Hartikainen&lt;/a&gt; for pointing out an error in the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-8160675192734235281?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/rJBri3xXR7s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/8160675192734235281/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/01/design-patterns-singleton-serieshow-to.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/8160675192734235281?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/8160675192734235281?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/rJBri3xXR7s/design-patterns-singleton-serieshow-to.html" title="Design Patterns - Singleton [Series][How-To]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-epOqhyQH4D4/Tr2HKw-kMoI/AAAAAAAAFw8/O3e9QdI7v64/s72-c/dp_misc.gif" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/01/design-patterns-singleton-serieshow-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MNR3w6eip7ImA9WhRTGUs.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-1372527292019264515</id><published>2010-01-10T17:41:00.000-05:00</published><updated>2011-11-10T17:51:36.212-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-10T17:51:36.212-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SSL" /><category scheme="http://www.blogger.com/atom/ns#" term="Gentoo" /><category scheme="http://www.blogger.com/atom/ns#" term="Linux" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><title>Create a SSL Certificate (Linux) [How-To]</title><content type="html">There are times that I want to set up a secure communication with the server I am working on. This might be because I want to run phpMyAdmin over SSL (I do not like unencrypted communications over the Internet), install a certificate for an eShop for a client or just for my personal use.
&lt;br /&gt;
&lt;br /&gt;
The first time I did this, I had to research on the Internet and after a bit of a trial and error I managed to get everything working. However if you do not do something on a regular basis you will forget. I am no exception to this rule hence this post to allow me to remember what I did and hopefully help you too.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Prerequisites:
&lt;/b&gt;&lt;br /&gt;
This how-to assumes that you are running Gentoo, however these instructions can easily be applied to any other Linux distribution.&lt;br /&gt;
&lt;br /&gt;
I need to check if &lt;a href="http://www.openssl.org/"&gt;openssl&lt;/a&gt; is installed:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;vanadium ~ # emerge --pretend dev-libs/openssl

These are the packages that would be merged, in order:

Calculating dependencies... done!
[ebuild &amp;nbsp; R &amp;nbsp; ] dev-libs/openssl-0.9.8l-r2&lt;/pre&gt;
&lt;br /&gt;
If you do not see the [R] next to the package (and you see a N for instance) that means that you need to install the package. Issuing:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;vanadium  ~ # emerge --verbose dev-libs/openssl&lt;/pre&gt;
&lt;br /&gt;
will do the trick.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Generate the Private Key
&lt;/b&gt;&lt;br /&gt;
I like to generate keys with a lot of bits. All of my certificates have 4096 bits. This is a personal preference and it does not hurt to keep that value. Your host or Signing Authority (like GoDaddy, VeriSign, Thawte etc.) might ask you in their instructions to generate one with 2048 bits so don't be alarmed there.&lt;br /&gt;
&lt;br /&gt;
Creating the RSA private key with 4096 bits using Triple-DES:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;vanadium ~ # openssl genrsa -des3 -out /root/vanadium.niden.net.locked.key 4096
Generating RSA private key, 4096 bit long modulus
.............................................................++
...........++
e is 65537 (0x10001)
Enter pass phrase for /root/vanadium.niden.net.locked.key:
Verifying - Enter pass phrase for /root/vanadium.niden.net.locked.key:&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Remove the passphrase from the Private Key&lt;/b&gt;&lt;br /&gt;
The key that was created earlier has a passphrase. Although this is good, it does have a side effect that any web server administrator does not like - the passphrase itself. Once the certificate is installed using the key (with the passphrase), every time that Apache is restarted, it will prompt the operator for the passphrase. This can be very inconvenient if your web server reboots in the middle of the night. Since Apache will be waiting for the passphrase, your site will be inaccessible.&lt;br /&gt;
&lt;br /&gt;
To avoid this inconvenience, I am removing the passphrase from the key. If you noticed the key that I have created above has the 'locked' phrase in its name. The reason is that I know that that particular key has the passphrase on it. I first need to copy the key and then remove the passphrase:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;vanadium ~ # cp -v vanadium.niden.net.locked.key vanadium.niden.net.key
`vanadium.niden.net.locked.key' -&amp;gt; `vanadium.niden.net.key'
vanadium ~ # openssl rsa -in vanadium.niden.net.locked.key -out vanadium.niden.net.key
Enter pass phrase for vanadium.niden.net.locked.key:
writing RSA key&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Generate the Certificate Signing Request (CSR)&lt;/b&gt;&lt;br /&gt;
The purpose of the CSR is to be sent to one of the Certificate Authorities (GoDaddy, VeriSign, Thawte etc.) for verification. Alternatively I can self-sign the CSR (see below).&lt;br /&gt;
&lt;br /&gt;
Upon generation of this CSR I am asked about particular pieces of information to be incorporated in the CSR. The most important piece of information that I need to ensure that is correct is the "&lt;strong&gt;Common Name&lt;/strong&gt;". The answer to that question has to be the name of my web server - vanadium.niden.net in my case.
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;em&gt;NOTE&lt;/em&gt;&lt;/strong&gt;: I am using the key without the passphrase.
&lt;br /&gt;
&lt;br /&gt;
The command to generate the CSR is as follows:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;vanadium ~ # openssl req -new -key vanadium.niden.net.key -out vanadium.niden.net.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Virginia
Locality Name (eg, city) []:Arlington
Organization Name (eg, company) [Internet Widgits Pty Ltd]:niden.net
Organizational Unit Name (eg, section) []:IT
Common Name (eg, YOUR name) []:vanadium.niden.net
Email Address []:domains@niden.net

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:&lt;/pre&gt;
&lt;br /&gt;
Once this step is completed, I open the CSR file with a text editor, copy the contents and paste them in the relevant field of the Certification Authority (in my case GoDaddy), so that they can verify the CSR and issue the certificate.
&lt;br /&gt;
&lt;br /&gt;
If however this is a development box or you do not want your certificate signed by a Certification Authority, you can check the section below on how to generate a self-signed certificate.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Generating a Self-Signed Certificate
&lt;/b&gt;&lt;br /&gt;
Generating a certificate valid for 365 days, I need to issue the following command:&lt;br /&gt;
&lt;br /&gt;
At this point you will need to generate a self-signed certificate because you either don't plan on having your certificate signed by a CA, or you wish to test your new SSL implementation while the CA is signing your certificate. This temporary certificate will generate an error in the client browser to the effect that the signing certificate authority is unknown and not trusted.
&lt;br /&gt;
&lt;br /&gt;
To generate a temporary certificate which is good for 365 days, issue the following command:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;vanadium ~ # openssl x509 -req -days 365 -in vanadium.niden.net.csr -signkey vanadium.niden.net.key -out vanadium.niden.net.crt
Signature ok
subject=/C=US/ST=Virginia/L=Arlington/O=niden.net/OU=IT/CN=vanadium.niden.net/emailAddress=domains@niden.net
Getting Private key&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Installation&lt;/b&gt;&lt;br /&gt;
For my system, the certificates are kept under /etc/apache2/ssl/ so I am going to copy them there (your need to adjust the instructions below to suit your system/installation):&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;vanadium ~ # cp -v vanadium.niden.net.key /etc/apache2/ssl/
vanadium ~ # cp -v vanadium.niden.net.crt /etc/apache2/ssl/&lt;/pre&gt;
&lt;br /&gt;
I also need to open the relevant file to enable the certificate
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;vanadium ~ # nano -w /etc/apache2/vhosts.d/00_default_ssl_vhost.conf&lt;/pre&gt;
&lt;br /&gt;
In that file I need to change the following directives:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;SSLCertificateFile /etc/ssl/apache2/vanadium.niden.net.crt
SSLCertificateKeyFile /etc/ssl/apache2/vanadium.niden.net.key&lt;/pre&gt;
&lt;br /&gt;
If my certificate was issued by a Certificate Authority, the files that I have received have the CA certificate file. I can enable it in the following line:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;SSLCACertificateFile /etc/ssl/apache2/vanadium.niden.net.ca-bundle.crt&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Restarting Apache&lt;/b&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre;"&gt;vanadium ~ # /etc/init.d/apache2 restart&lt;/span&gt;&lt;br /&gt;
&lt;pre&gt;vanadium ~ # /etc/init.d/apache2 restart
 * Stopping apache2 ...                              [ ok ]
 * Starting apache2 ...                              [ ok ]&lt;/pre&gt;
&lt;br /&gt;
Navigating to &lt;strong&gt;https://vanadium.niden.net&lt;/strong&gt; should tell me if what I did was successful or not. If your browser (Google Chrome in my case) gives you a bright red screen with all sorts of warnings, that means that
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;either you self signed the certificate - in which case it complains about the certificate not being signed by a Certificate Authority or&lt;/li&gt;
&lt;li&gt;you made a mistake and the Common Name in the certificate is not the same as the host name.&lt;/li&gt;
&lt;/ul&gt;
Both these errors are easy to fix.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-1372527292019264515?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/maQsEg75ghs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/1372527292019264515/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/01/create-ssl-certificate-linux-how-to.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/1372527292019264515?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/1372527292019264515?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/maQsEg75ghs/create-ssl-certificate-linux-how-to.html" title="Create a SSL Certificate (Linux) [How-To]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/01/create-ssl-certificate-linux-how-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8GRns7fip7ImA9WhRSEEk.&quot;"><id>tag:blogger.com,1999:blog-1710151540605737130.post-5835278926316517350</id><published>2010-01-06T17:35:00.000-05:00</published><updated>2011-11-11T15:37:07.506-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-11T15:37:07.506-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="Patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="Series" /><category scheme="http://www.blogger.com/atom/ns#" term="How-To" /><category scheme="http://www.blogger.com/atom/ns#" term="Design" /><title>Design Patterns - Series [Series][How-To]</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-epOqhyQH4D4/Tr2HKw-kMoI/AAAAAAAAFw8/O3e9QdI7v64/s1600/dp_misc.gif" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="291" src="http://3.bp.blogspot.com/-epOqhyQH4D4/Tr2HKw-kMoI/AAAAAAAAFw8/O3e9QdI7v64/s320/dp_misc.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
A lot of developers – including myself – have at some point in their programming careers found themselves repeating a task that they have completed for a previous project or for a previous part of the same project.
&lt;br /&gt;
&lt;br /&gt;
This problem of repeating code is solved by design patterns. A design pattern is the way that the code must be structured so that the problem at hand can be solved. The characteristics of design patterns are:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt; – it lets other programmers know what this pattern does.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Problem&lt;/strong&gt; – where the pattern can be applied&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Solution&lt;/strong&gt; – how this pattern is implemented&lt;/li&gt;
&lt;/ul&gt;
In the course of the next few weeks, I will publish a series of blog posts, where &amp;nbsp;I will try to present you with some common design patterns and how I have understood their use. Most books and online materials concentrate on just presenting the issue at hand and do not focus on how we ended up there. In these blog post series I will try to show you what I found along the way and how I solved each problem in turn.
&lt;br /&gt;
&lt;br /&gt;
As usual comments are more than welcome.
&lt;br /&gt;
&lt;br /&gt;
The design patterns I will discuss in posts of these series are as:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://www.niden.net/2010/01/design-patterns-singleton-series-how-to/"&gt;Singleton Pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.niden.net/2010/01/design-patterns-factory-series-how-to/"&gt;Factory Pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Registry Pattern&lt;/li&gt;
&lt;li&gt;Decorator Pattern&lt;/li&gt;
&lt;li&gt;Adapter Pattern&lt;/li&gt;
&lt;li&gt;Iterator Pattern&lt;/li&gt;
&lt;li&gt;Strategy Pattern&lt;/li&gt;
&lt;li&gt;Active Record Pattern&lt;/li&gt;
&lt;li&gt;Value Object Pattern&lt;/li&gt;
&lt;li&gt;Model View Controller Pattern&lt;/li&gt;
&lt;li&gt;MockObject Pattern&lt;/li&gt;
&lt;li&gt;Observer Pattern&lt;/li&gt;
&lt;li&gt;Proxy Pattern&lt;/li&gt;
&lt;li&gt;Table Data Gateway Pattern&lt;/li&gt;
&lt;li&gt;Data Mapper Pattern&lt;/li&gt;
&lt;/ol&gt;
You can check this blog every week, &lt;a href="http://feeds.feedburner.com/nikosdimopoulos"&gt;subscribe to the RSS feed&lt;/a&gt;, &lt;a href="http://twitter.com/nikosdimopoulos"&gt;follow me on Twitter&lt;/a&gt; or &lt;a href="https://profiles.google.com/104235485963468152376"&gt;follow my Google Reader&lt;/a&gt; (or all of the above).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1710151540605737130-5835278926316517350?l=www.niden.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/niden/~4/iahZP1G1O_s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.niden.net/feeds/5835278926316517350/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.niden.net/2010/01/design-patterns-series-serieshow-to.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/5835278926316517350?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1710151540605737130/posts/default/5835278926316517350?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/niden/~3/iahZP1G1O_s/design-patterns-series-serieshow-to.html" title="Design Patterns - Series [Series][How-To]" /><author><name>Nikolaos Dimopoulos</name><uri>https://profiles.google.com/104235485963468152376</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-tZZYYyDcFfs/AAAAAAAAAAI/AAAAAAAAr_U/MLSOKUmO8Zo/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-epOqhyQH4D4/Tr2HKw-kMoI/AAAAAAAAFw8/O3e9QdI7v64/s72-c/dp_misc.gif" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>Charles Town, WV, USA</georss:featurename><georss:point>39.2889903 -77.8597175</georss:point><georss:box>39.2398328 -77.9386815 39.3381478 -77.7807535</georss:box><feedburner:origLink>http://www.niden.net/2010/01/design-patterns-series-serieshow-to.html</feedburner:origLink></entry></feed>

