<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Deep Shift Labs Development Blog</title>
	
	<link>http://www.deepshiftlabs.com/dev_blog</link>
	<description />
	<lastBuildDate>Fri, 06 Apr 2012 03:31:07 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en-us</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/DeepShiftLabsDevelopmentBlog" /><feedburner:info uri="deepshiftlabsdevelopmentblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>DeepShiftLabsDevelopmentBlog</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>How do we use Kayako – Part II</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/LQaZJVVFh04/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=1564&amp;lang=en-us#comments</comments>
		<pubDate>Thu, 05 Apr 2012 08:27:00 +0000</pubDate>
		<dc:creator>Igor Kryltsov</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=1564</guid>
		<description><![CDATA[
In my second post about Kayako, I would like to show what we managed to achieve. We posted our list of requirements for a help desk system in the previous post. I must admit that the setup took a lot of time we discovered a few bugs in Kayako along the way. Some of them [...]]]></description>
			<content:encoded><![CDATA[<div style="float: left;"><a href="http://www.kayako.com/" target="_blank"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/02/kayako_part_2.gif" alt="How do we use Kayako - Part II" width="288" height="192" /></a></div>
<p>In my second post about <a href="http://www.kayako.com/" target="_blank">Kayako</a>, I would like to show what we managed to achieve. We posted our list of requirements for a help desk system in the <a href="http://www.deepshiftlabs.com/dev_blog/?p=1398&amp;lang=en-us" target="_blank">previous</a> post. I must admit that the setup took a lot of time we discovered a few bugs in Kayako along the way. Some of them were quite serious. The rest can be classified as defects as it looked like some functionality which was added on top of the existing system and implementation was not well thought through by Kayako.</p>
<p>Almost all errors were fixed by Kayako developers soon enough. However, we had one error which took us two weeks to fix. We <a href="http://forums.kayako.com/threads/whoops-and-more.27657/page-3#post-133398" target="_blank">exchanged</a> emails with Kayako until they agreed to provide us with their open source code. From that point we tracked the bug within an hour. After setting up Kayako, as we have been making web applications for quite a long time now, our hands itched to make our own simple help desk system. If you are like us, you will understand, or at least will agree with us upon closer acquaintance with Kayako.<br />
<span id="more-1564"></span><br />
In the process of setting up Kayako I wrote as much as 126 posts in their forum. Almost all of them were answered by a wonderful man, a forum guru &#8211; <a href="http://forums.kayako.com/members/garygbm.26371/" target="_blank">Gary</a>, who, incidentally, is not a Kayako employee. Gary had no avatar on the forum and I, being impressed by his experience and desire to help, offered him an avatar, which he gladly accepted.</p>
<p><img class="aligncenter" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/Gary_Igor_Kayako_forum.png" alt="" /></p>
<p>We were able to achieve our goal. We have one support system that is used for everything we do.</p>
<p><strong>1. Working with clients</strong></p>
<p>Each client has his own Kayako portal.</p>
<p><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Client’s Kayako Help Desk portal" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/client_Kayako.png" alt="Client’s Kayako Help Desk portal" /></p>
<p style="text-align: center;">Fig. 1 Client’s Kayako Help Desk portal</p>
<p>As you can see an unauthorized user can only access the login page. Moreover, the portal is closed with htaccess directly from Kayako (they have such an option). Users of such client’s portals are created by us in advance. The number of users is small and constant for each client. We created special mailboxes CLIENT_A@support.deepshiftlabs.com, served by GMail. Kayako will not accept mail from unregistered users in these portals. The number of such portals is not limited by the Kayako license. Limitations &#8211; all the portals will be on the same URL &#8211; http://support.deepshiftlabs.com. The only difference is in the parameter / index.php?/CLIENT_A. Ideally we would like to be able to create portals, as http://CLIENT_A.deepshiftlabs.com and suggest Kayako to find ways to license this scheme.</p>
<p><strong>2. Integration with our web service</strong></p>
<p>We have a web service &#8211; <a href="http://www.nerrvana.com" target="_blank">Nerrvana</a>.</p>
<p><a title="Click to see real web page" href="http://support.deepshiftlabs.com/index.php?/Nerrvana" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Our web service help desk portal" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/Nerrvana_Kayako.png" alt="Our web service help desk portal" /></a></p>
<p style="text-align: center;">Fig. 2 Our web service help desk portal</p>
<p><em>Here and below, links from screen shots lead to real pages of our Kayako installation. For some reason Kayako developers decided that one portal user will never visit another one and they decided to keep a reference to a portal template in a cookie. This means that by visiting our portals it will seem that they have broken styles. If you would knew how it hurt during Kayako customisation, especially before we realized that the problem is not in our settings, but in the cookie you need to wipe every time before visiting a new Kayako portal, for example, from Firebug. Another way would be to use different browsers during the configuration phase.</em></p>
<p><img class="aligncenter" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/weird_Kayako_cookie.png" alt="" /></p>
<p>Here you see a portal with all the options available &#8211; news, sign up, create a new ticket. In here we do not use GMail and handle incoming emails ourselves. We do not even use a spam filter and Kayako reads incoming emails using IMAP. The highlight of this portal is that it is fully integrated with Nerrvana. To begin with, we have implemented a way for Nerrvana users to create help desk tickets without leaving Nerrvana’s UI.</p>
<p><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Integration with Kayako in Nerrvana" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/support_Nerrvana.png" alt="Integration with Kayako in Nerrvana" /></p>
<p style="text-align: center;">Fig. 3 Integration with Kayako in Nerrvana</p>
<p>Kayako’s API allows us to create a new ticket, and using API, add to the ticket all the necessary information about the problem that would help to resolve it faster.</p>
<p>But not everything is as it should be, and the problem was to synchronise user passwords. Why do we need this synchronisation? We want to provide excellent user experience. What could be more convenient than having a single password in Nerrvana and in Help Desk? To understand the problem we faced let&#8217;s consider a few scenarios.</p>
<p>The potential client (let&#8217;s call him &#8220;A&#8221;) emails the issue to contact@nerrvana.com. Kayako creates a ticket and a new account. Further, &#8220;A&#8221; registers in Nerrvana (we assume he uses the same email) and different password. Well, we can change it in Kayako through the API. But what if &#8220;A&#8221; will go to the Kayako portal and will change the password there?</p>
<p><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Kayako change password form" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/change_password_form.png" alt="Kayako change password form" /></p>
<p style="text-align: center;">Fig. 4 Kayako change password form</p>
<p>We cannot disable changing a password in Kayako because the portal is used not only by customers but also by potential customers who do not have Nerrvana account. In addition all portal visitors have access to &#8220;Forgot Password&#8221; in Kayako, which again allows you to change your password. That is we can synchronise the password changes with Kayako, but not vice versa.</p>
<p><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Kayako password recovery form" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/lost_password_form.png" alt="Kayako password recovery form" /></p>
<p style="text-align: center;">Fig. 5 Kayako password recovery form</p>
<p>I <a href="http://forums.kayako.com/threads/lost-password.29387/#post-140133" target="_blank">described</a> the problem in Kayako’s forum, hoping that we are not the first who ran into it and luckily, received the answer that satisfied us. It remained only to sign an <a href="http://en.wikipedia.org/wiki/Non-disclosure_agreement" target="_blank">NDA</a> and get the code of two Kayako classes participating in resetting and changing a password. After that, we created a secret Nerrvana page, which we call after Kayako has finished the password changing operation. This page checks whether this user is also a Nerrvana user and if so &#8211; changes the password in Nerrvana.</p>
<p>As a result we have the following working scheme:</p>
<p>- User registers in Nerrvana and does not have Kayako account yet. Nerrvana creates an account as well as an account in Kayako via API, but without sending an e-mail from Kayako. Our email already contains instructions on accessing the Help Desk. Why bombard a new client with two e-mails? Kayako’s API has an option to supress registration email when an account is created via API.</p>
<p>- User registers in Nerrvana while having a previously created Kayako account. Nerrvana creates an account and changes his password in Kayako through the API to match his Nerrvana password.</p>
<p>- The potential client asks a question while not having a Kayako account. Kayako creates his account and sends him his user name and password by e-mail.</p>
<p>- The potential client asks a question while having a Kayako account. Nothing happens. Kayako simply creates a new ticket.</p>
<p>- The user changes the password in Nerrvana or resets forgotten one. We change the password via the API in Kayako too.</p>
<p>- Nerrvana’s user changes or resets password in Kayako. We use our secret script which we injected into Kayako’s code to change his password in Nerrvana.</p>
<p><strong>3. Using Kayako to support software users buy, download and install</strong></p>
<p>We created the first web application in the <a href="http://www.starty.co">Startyco</a> set &#8211; Answers, which you can buy, download and install. Again, we use the Kayako portal to support our customers.</p>
<p><a title="Click to see real web page" href="http://support.deepshiftlabs.com/index.php?/Startyco" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Kayako portal to support downloadable web application" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/Startyco_Kayako.png" alt="Kayako portal to support downloadable web application" /></a></p>
<p style="text-align: center;">Fig. 6 Kayako portal to support downloadable web application<br />
(gradient in the header looks pretty ugly on a screenshot)</p>
<p>When you buy our application, we register the purchase in a special small (just 5 tables) database. We record the license granted, its type (trial or permanent and which domain it is issued for), client details. If the account does not exist yet in Kayako, we create it. Accounts can be created before purchase if a potential customer sent an email to us asking some questions. We use the Kayako database to authenticate clients on the site of our product – answers.starty.co, and tables in our own small database to determine purchases and new product upgrades available for download.</p>
<p>There are two possible scenarios. The first – a customer asked a few questions, Kayako created an account automatically and sent an email with account details. We answered his questions, and now, if a customer buys a product he will be able additionally login to answers.starty.co with his Kayako account. On purchase we simply add data we need to our small database I mentioned. The second &#8211; a customer buys the product or downloads a demo version. If account was not found in Kayako we create it through the API and at the same time record user information in our database.</p>
<p>When you create a new user via Kayako’s API, you can specify whether to send him an email with account details or not. A password is required for viewing and creating tickets from the web interface in Kayako. In this case, unlike Nerrvana, sending an email is appropriate. A user loads the product and at the same time receives an email from Kayako with access details to our help desk system. In Nerrvana we instruct Kayako via API not to send our own email to the newly registered user, because we want him to have only one email from Nerrvana with all info needed. So if you sell a downloadable product (not a web service) you can simply add your own tables into your database, register new customers directly in Kayako and add additional information in your own database.</p>
<p>Finally, in case if someone wanders into a default portal (the one with no parameters after URL), we have completely changed it by putting more buttons on it, redirecting to the portals of Nerrvana and Startyco. By the way, look at favicons of a client, Nerrvana, Startyco and default portals on screenshots above – we changed them too.</p>
<p><a title="Click to see real web page" href="http://support.deepshiftlabs.com" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Default Help Desk URL has no portals but links to them" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/default_Kayako.png" alt="Default Help Desk URL has no portals but links to them" /></a></p>
<p style="text-align: center;">Fig.7 Default Help Desk URL has no portals but links to them</p>
<p>In my next post I try to give step by step setup instructions for the portals we use. Hopefully this will save you some time.<br />
</p>
<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/LQaZJVVFh04" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=1564&amp;lang=en-us</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=1564&amp;lang=en-us</feedburner:origLink></item>
		<item>
		<title>CentOS 6 minimal install on VMware with kickstart</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/ZiwR6uhrxkY/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=1571&amp;lang=en-us#comments</comments>
		<pubDate>Mon, 19 Mar 2012 13:21:55 +0000</pubDate>
		<dc:creator>Igor Kryltsov</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=1571</guid>
		<description><![CDATA[In this post I would like to show how you can install bare minimum CentOS 6 system on VMware using a kickstart file. You will need to have a VMWare Workstation 8 installed and load either i386 netinstall image or the x86_64 bit version. My links point to the closest CentOS mirrors for me, and [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-thumbnail wp-image-1524" style="padding: 5px 20px 10px 0;" title="CentOS 6 minimum install on VMware with kickstart" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/vmware_centos_tn.gif" alt="" width="195" height="113" />In this post I would like to show how you can install bare minimum CentOS 6 system on VMware using a kickstart file. You will need to have a VMWare Workstation 8 installed and load either <a href="http://mirror.aarnet.edu.au/pub/centos/6.2/isos/i386/CentOS-6.2-i386-netinstall.iso" target="_blank">i386</a> netinstall image or the <a href="http://mirror.aarnet.edu.au/pub/centos/6.2/isos/x86_64/CentOS-6.2-x86_64-netinstall.iso" target="_blank">x86_64</a> bit version. My links point to the closest CentOS mirrors for me, and you will load it from <a href="http://isoredirect.centos.org/centos/6/isos/x86_64/" target="blank">one</a> close to you.<br />
We will not need <a href="http://www.slysoft.com/en/virtual-clonedrive.html" target="_blank">Virtual CloneDrive</a> as VMware is capable of running install directly from .iso file.</p>
<p>Let&#8217;s begin by creating a new virtual machine.<br />
<span id="more-1571"></span><br />
<img class="aligncenter" title="Step 1 - Create a new virtual machine" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_0.png" alt="Step 1 - Create a new virtual machine" /></p>
<p style="text-align: center;">Fig. 1 Launch new virtual machine wizard</p>
<p><img class="aligncenter" title="Step 2 - Select Workstation 8.0" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_1.png" alt="Step 2 - Select Workstation 8.0" /></p>
<p style="text-align: center;">Fig. 2 Select Workstation 8.0</p>
<p><img class="aligncenter" title="Step 3 - Point to loaded netinstall image" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_2.png" alt="Step 3 - Point to loaded netinstall image" /></p>
<p style="text-align: center;">Fig. 3 Point to loaded netinstall image</p>
<p><img class="aligncenter" title="Step 4 - I install CentOS 6.2 64 bit" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_3.png" alt="Step 4 - I install CentOS 6.2 64 bit" /></p>
<p style="text-align: center;">Fig. 4 I install CentOS 6.2 64 bit</p>
<p><img class="aligncenter" title="Step 5 - Select location for VM files" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_4.png" alt="Step 5 - Select location for VM files" /></p>
<p style="text-align: center;">Fig. 5 Select location for VM files</p>
<p><img class="aligncenter" title="Step 6 - I have 4 cores on i7 so I give 2 of them to VM" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_5.png" alt="Step 6 - I have 4 cores on i7 so I give 2 of them to VM" /></p>
<p style="text-align: center;">Fig. 6 I have 4 cores on i7 so I give 2 of them to VM</p>
<p><img class="aligncenter" title="Step 7 - I have 16Gb RAM and give 2Gb to CentOS VM" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_6.png" alt="Step 7 - I have 16Gb RAM and give 2Gb to CentOS VM" /></p>
<p style="text-align: center;">Fig. 7 I have 16Gb RAM and give 2Gb to CentOS VM</p>
<p><img class="aligncenter" title="Step 8 - I use static IP's and want to use bridged neworking" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_7.png" alt="Step 8 - I use static IP's and want to use bridged neworking" /></p>
<p style="text-align: center;">Fig. 8 I use static IP&#8217;s and want to use bridged networking</p>
<p><img class="aligncenter" title="Step 9" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_8.png" alt="Step 9" /></p>
<p style="text-align: center;">Fig. 9 Accept defaults</p>
<p><img class="aligncenter" title="Step 10" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_9.png" alt="Step 10" /></p>
<p style="text-align: center;">Fig. 10 Accept defaults</p>
<p><img class="aligncenter" title="Step 11" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_10.png" alt="Step 11" /></p>
<p style="text-align: center;">Fig. 11 Accept defaults</p>
<p><img class="aligncenter" title="Step 12 - With minimal install VM file will be less than 1G" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_11.png" alt="Step 12 -With minimal install VM file will be less than 1G" /></p>
<p style="text-align: center;">Fig. 12 With minimal install VM file will be less than 1G</p>
<p><img class="aligncenter" title="Step 13" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_12.png" alt="Step 13" /></p>
<p style="text-align: center;">Fig. 13 Accept defaults</p>
<p><img class="aligncenter" title="Step 14 - VM setup is completed" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_13.png" alt="Step 14 - VM setup is completed" /></p>
<p style="text-align: center;">Fig. 14 VM setup is completed</p>
<p><img class="aligncenter" title="Step 15 - Press Tab here to plug kickstart in" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_15.png" alt="Step 15 - Press Tab here to plug kickstart in" /></p>
<p style="text-align: center;">Fig. 15 Press Tab here to plug kickstart in</p>
<p>Now we have to say a few words about kickstart. There are <a href="http://www.centos.org/docs/5/html/5.1/Installation_Guide/s1-kickstart2-startinginstall.html" target="_blank">plenty of</a> options for &#8216;ks&#8217; parameter. I used web way. This is <a href="http://www.chepkov.com/centos6.cfg" target="_blank">where</a> my kickstart was but Vadym, who created it for me, may delete it later so I put in in here.</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1571code2'); return false;">View Code</a> TXT</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p15712"><td class="code" id="p1571code2"><pre class="txt" style="font-family:monospace;">text
skipx
install
url --url http://mirror.cogentco.com/pub/linux/centos/6/os/x86_64/
repo --name=epel --baseurl=http://download.fedoraproject.org/pub/epel/6/x86_64/
repo --name=updates --baseurl=http://mirror.cogentco.com/pub/linux/centos/6/updates/x86_64/
lang en_US.UTF-8
keyboard us
rootpw 123456
firewall --disabled
authconfig --enableshadow --passalgo=sha512
selinux --disabled
timezone Etc/UTC
bootloader --location=mbr
zerombr
clearpart --all --initlabel
part /boot --fstype ext4 --fsoptions=&quot;noatime&quot; --size=200
part pv.1 --size 1 --grow
volgroup vg0 --pesize=4096 pv.1
logvol / --fstype ext4 --fsoptions=&quot;noatime&quot; --name=root --vgname=vg0 --size=8192
logvol swap --fstype swap --name=swap --vgname=vg0 --size 2048
logvol /var --fstype ext4 --fsoptions=&quot;noatime,nodev&quot; --name=var --vgname=vg0 --size=4096
logvol /home --fstype ext4 --fsoptions=&quot;noatime,nodev&quot; --name=home --vgname=vg0 --size=2048
&nbsp;
services --enabled=sendmail,network,ntpd,ntpdate
&nbsp;
reboot
&nbsp;
%packages --nobase
epel-release
openssh-clients
openssh-server
yum
at
acpid
vixie-cron
cronie-noanacron
crontabs
logrotate
ntp
ntpdate
tmpwatch
rsync
sendmail
mailx
which
wget
-postfix
-prelink
-selinux-policy-targeted
%end</pre></td></tr></table></div>

<p>I do not want to go into true minimal install discussion as I trust Vadym <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Let&#8217;s say it is one of the minimal install kickstarts. You can get the most benefits from kickstarts if you are going to install many systems or move them around. We extensively use kickstarts in <a href="http://www.nerrvana.com" target="_blank">Nerrvana</a> under Vadym&#8217;s guidance. Our core, FTPS servers, Selenium Hub and CentOS RC VMs are all kickstarted. We can move them to another hoster pretty easily and our kickstarts reflect all packages installed as well as our own RPM&#8217;s and customisations we need for each system.</p>
<p>In this case we are not going to reinstall or move a system &#8211; we just want to start it and not waste time clicking around selecting packages and creating file systems. Basically we want to save time. In future posts we may share different tips of our real kickstarts as well as the way we create Windows based Xen VMs with different browsers for Nerrvana. We simply want to share what we learned while building Nerrvana so others can benefit creating their own Selenum testing systems.</p>
<p>Back to our topic. Put your kickstart file to make it available via HTTP. You can simply start IIS and add this file to default IIS home directoty, for example.</p>
<p><img class="aligncenter" title="Step 16 - Add kickstart parameters and hit Enter" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_16.png" alt="Step 16 - Add kickstart parameters and hit Enter" /></p>
<p style="text-align: center;">Fig. 16 Add kickstart parameters and hit Enter</p>
<p><img class="aligncenter" title="Step 17 - Installation starts" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_17.png" alt="Step 17 - Installation starts" /></p>
<p style="text-align: center;">Fig. 17 Installation starts</p>
<p><img class="aligncenter" title="Step 18 - 'Asknetwork' param at work" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_18.png" alt="Step 18 - 'Asknetwork' param at work" /></p>
<p style="text-align: center;">Fig. 18 &#8216;Asknetwork&#8217; param at work</p>
<p><img class="aligncenter" title="Step 19 - Enter network details" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_19.png" alt="Step 19 - Enter network details" /></p>
<p style="text-align: center;">Fig. 19 Enter network details</p>
<p><img class="aligncenter" title="Step 20 - Installation resumes" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_20.png" alt="Step 20 - Installation resumes" /></p>
<p style="text-align: center;">Fig. 20 Installation resumes</p>
<p><img class="aligncenter" title="Step 21 - Use Alt+F3 to see logs while installation goes on" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_21.png" alt="Step 21 - Use Alt+F3 to see logs while installation goes on" /></p>
<p style="text-align: center;">Fig. 21 Use Alt+F3 to see logs while installation goes on</p>
<p><img class="aligncenter" title="Step 22 - OS and packages from kickstart installed" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_22.png" alt="Step 22 - OS and packages from kickstart installed" /></p>
<p style="text-align: center;">Fig. 22 OS and packages from kickstart installed</p>
<p><img class="aligncenter" title="Step 23 - All done. Now install what you want." src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/install_23.png" alt="Step 23 - All done. Now install what you want." /></p>
<p style="text-align: center;">Fig. 23 All done. Now install what you want.</p>
<p><img class="aligncenter" title="Step 24 - Takes 725Mb of disk space" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/03/2012-03-17_154625.png" alt="Step 24 - Takes 725Mb of disk space" /></p>
<p style="text-align: center;">Fig. 24 Takes 725Mb of disk space</p>
<p>Now you can login as root/123456, change password, set sshd, disable root login via ssh, create an account for youself, install MySQL, PHP etc.<br />
</p>
<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/ZiwR6uhrxkY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=1571&amp;lang=en-us</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=1571&amp;lang=en-us</feedburner:origLink></item>
		<item>
		<title>Writing beautiful HTML emails</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/lOyNeBY43bs/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=1518&amp;lang=en-us#comments</comments>
		<pubDate>Mon, 06 Feb 2012 23:54:42 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=1518</guid>
		<description><![CDATA[As you know we are about to launch our system – Nerrvana. It is time for the finale, hang the curtains, so to say &#8211; to prepare some nice templates for emails sent by the system. ‘A nice’ means it has to be in HTML format.
In the design of the system’s site we used loadable [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://browse.deviantart.com/?q=letterbox&amp;order=9&amp;offset=0#/dmyu8q" target="_blank"><img class="alignleft size-thumbnail wp-image-1524" style="padding: 5px 20px 10px 0;" title="Letter box" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/02/Letterbox_by_umersaud.jpg" alt="" width="300" height="225" /></a>As you <a href="http://www.deepshiftlabs.com/sel_blog/?p=1827&amp;lang=en-us" target="_blank">know</a> we are about to launch our system – Nerrvana. It is time for the finale, hang the curtains, so to say &#8211; to prepare some nice templates for emails sent by the system. ‘A nice’ means it has to be in HTML format.</p>
<p>In the design of the system’s <a href="http://www.nerrvana.com" target="_blank">site</a> we used loadable fonts and of course we would not mind using them in the emails. However, according to <a href="http://www.campaignmonitor.com/blog/post/3044/does-font-face-work-in-email/" target="_blank">Campaign Monitor</a>, in recent years nothing has changed &#8211; external fonts cannot be used in emails. Ok, we will take this as a given and will only use CSS and standard fonts. Googling this topic brings a tip on HTML coding for emails from <a href="http://kb.mailchimp.com/article/how-to-code-html-emails" target="_blank">MailChimp</a> where they suggest to use inline CSS instructions, i.e. include the styles directly in the html tags. I will illustrate, using GMail as an example.<br />
<span id="more-1518"></span><br />
We create a simple email that is sent to the newly registered users. Here&#8217;s how it looks in FireFox; pretty good.</p>
<p><img class="aligncenter size-full wp-image-1519" title="Email sample directly in the browser" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/02/email_in_ff_1.png" alt="" width="470" height="280" /></p>
<p>Now I have sent it to my GMail account and let’s look how it renders.</p>
<p><img class="aligncenter size-full wp-image-1521" style="padding-top: 10px;" title="First look at email in the GMail" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/02/email_in_ff_gmail_1.png" alt="" width="470" height="308" /></p>
<p>Let&#8217;s play a game of &#8220;Find the 10 differences.&#8221; What do we see? Both size and font type are different. Why? When we create HTML page layout, we rely on the inheritance of the styles. Nested styles inherit their parents properties and for some reason Firefox calculated the style of the font size for the table cells in 16 pixels. In the case with mail services all is more complex. Forget about inheritance &#8211; external (GMail’s ones in this case) styles can override your inheritance at any time, as can be seen on the screenshots. Here is the piece of code we are interested in.</p>
<p>HTML in Firebug …</p>
<p><img class="aligncenter size-full wp-image-1522" style="padding-top: 10px;" title="GMail styles first screen" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/02/gmail_styles_1.png" alt="" width="433" height="211" /></p>
<p>… and his current styles</p>
<p><img class="aligncenter size-full wp-image-1541" style="padding: 10px 0;" title="GMail styles 2" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/02/gmail_styles_3.png" alt="" width="676" height="216" /></p>
<p>Here the font size was calculated correctly, 22 pixels were inherited from parent’s div <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>In this example, as you understand, an HTML table is used to show a user name and password. Yes, do not throw spoiled vegetables at me. If you read the MailChimp article by following the link above, in paragraph 9 you will see this comment:</p>
<blockquote><p>Inline CSS is safer, and plain-old FONT tags are safest (code like it&#8217;s 1996, remember?).</p></blockquote>
<p>They were not kidding about the code in 90s style. It is true. Well, I digress, so we have a table located in the div’s, here it is:</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1518code4'); return false;">View Code</a> HTML</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p15184"><td class="code" id="p1518code4"><pre class="html" style="font-family:monospace;">&lt;div style=&quot;font-size: 22px; padding: 20px 0 30px 0; font-family: verdana;&quot;&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: right; width: 50%;&quot;&gt;Username:&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Alibaba&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: right;&quot;&gt;Password:&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;sim-sim&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
.....&lt;/div&gt;</pre></td></tr></table></div>

<p>What can we do here? That&#8217;s right, set your table styles to those that will override GMail ones. So we quickly copy-paste font styles into the table tags, like this &#8211; &lt;table style=&#8221;font-size: 16px; font-family: verdana;&#8221;&gt;. And here is the desired result:</p>
<p><img class="aligncenter size-full wp-image-1520" title="Final version of email in the GMail" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2012/02/email_in_ff_gmail2_1.png" alt="" width="470" height="274" /></p>
<p>As you see, it makes sense to apply styles to all elements surrounding content, leaving Google and others alike no chance to override them. Beautiful letters to you in all popular email services and clients!<br />
</p>
<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/lOyNeBY43bs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=1518&amp;lang=en-us</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=1518&amp;lang=en-us</feedburner:origLink></item>
		<item>
		<title>How do we use phpBB</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/LCYD2nCeyI4/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=928&amp;lang=en-us#comments</comments>
		<pubDate>Fri, 28 Oct 2011 09:05:57 +0000</pubDate>
		<dc:creator>Igor Kryltsov</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=928</guid>
		<description><![CDATA[

Writing this post was quite easy as we have already written about a way we use project management system and its’ connection to the forum. I decided  to add some stats:
Board started: 15/Jan/2009 2:16 am (no, we are not only launching boards at night)
Number of posts: 12705
Number of topics: 537
Number of users: 26
Number of [...]]]></description>
			<content:encoded><![CDATA[<div style="float: left;"><a href="http://www.phpbb.com/" target="_blank"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/php_bb.png" alt="How do we use phpBB" width="199" height="125" /></a></div>
<p><br />
Writing this post was quite easy as we have already <a href=" http://www.deepshiftlabs.com/dev_blog/?p=927&amp;lang=en-us" target="_blank">written</a> about a way we use project management system and its’ connection to the forum. I decided  to add some stats:</p>
<p>Board started: 15/Jan/2009 2:16 am (no, we are not only launching boards at night)<br />
Number of posts: 12705<br />
Number of topics: 537<br />
Number of users: 26<br />
Number of attachments: 2677<br />
Size of posted attachments: 513.56 Mb<br />
Database size: 89.3 Mb<br />
Posts per day: 12.61<br />
Attachments per day: 2.66</p>
<p>These are for three developers who are engaged in work continuously and the system administrator. All other activity is from customers and two guys who have tried to work with us some time ago.</p>
<p>This is a breakdown of posts inside our team:<br />
Igor &#8211; 6484<br />
Dmitry &#8211; 2516<br />
Alexander &#8211; 2843<br />
Vadym (systems administrator) &#8211; 252</p>
<p>I decided it will be better to let you see it all first. Taking into account my <a href="http://screenshoots.deepshiftlabs.com/" target="_blank">addiction</a> to screenshots with notes inside I made this screenshot (click to enlarge):<br />
<span id="more-928"></span><br />
<a title="Click to enlarge" href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/php_BB.png" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="phpBB" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/php_BB_720.png" alt="Click to enlarge" /></a></p>
<p>And finally, share some of the nuances.</p>
<p>It is important to give topics meaningful names and even more – when you reply change the subject to adjust to your message. You will agree that having one hundred replies on a topic with the name &#8216;What do you think about …?&#8217; which all have subjects &#8216;Re: What do you think about …?&#8217; do not make searching and working inside the board very pleasant. This is your team board – take care of it.</p>
<p>Sometimes you start discussing a task inside a topic but it quickly breaks into different subjects all mixed up. I advise to stop and create a new forum and split existing discussions into different topics. In phpBB you can use Merge topic or Move posts to do so.  You will most likely do it anyway later. To give you an example we started working on our first web application in starty.co family of products and discussions started inside a topic as a product is pretty simple, we thought.  It just seemed that a dozen more posts, and we&#8217;re done. When it became clear that we are not quite finished and more and more posts were created, I spent about two hours creating the right structure.  I created a forum-category, created forums for each starty.co product and a forum to discuss common concepts related to all of them in it and then threw the messages to the newly created forums by subject. It is not a disaster, but quite boring work. If you detect this sooner you will have less of it.</p>
<p>When you write a message &#8216;one more thing&#8217; often comes to mind and this thing often is not related to what you wrote. You write about architecture and this is about design or security. Do not be lazy – finish your current post and create a new post just with this thing in a right place. That is not to create islands of discussion A inside discussion B. When you will need to reread A you will not remember that something important about A is written in B.</p>
<p>Split all forum users into groups (us, clients, apprentices) and administer groups. The phpBB administrative interface is overwhelming for a small group of users, so the less time you spend there &#8211; the better for you.</p>
<p>In many forums it is handy to create Announcements or Stickies. For me, there&#8217;s no difference as I use them to place a topic at the top inside a forum. For example, in forums where we discuss articles in our blog I mark as announcements not yet published posts. It is convenient to have things you work on now in a separate section which is always at the top. The forum clients have access to uses an announcement topic as a place where updates are recorded. All posts in it are messages about upgrades on production and test systems, which version they run and what changes each new version introduces. But following our rules we do not explain each change or piece of functionality or a bug but just list them and create links to separate forums, clients also have access to, and can follow to read more details.</p>
<p>We try to discuss important things in the forum, and not on Skype and in the mail, because everyone understands that a couple of week’s later things will be forgotten. Seeking dialogues in different places is annoying and takes time. The key to the preceding sentence is the phrase &#8216;important things&#8217;. That is, we use Skype and e-mail of course too. Important points will still find its place in the forum in the form of: &#8216;We discussed on Skype so-and-so. We decided to do thus and thus.&#8217; With emails it is much easier &#8211; Ctrl-c and Ctrl-v but only key information is copy/pasted.</p>
<p>Each of us has developed his unique style of work with the forum. For example, Vadym does not like a forum at all, so we communicate with him by mail, and then transfer important bits to the forum.  Alexander &amp; I go in the forum when we receive new messages in the mail, and Dmitry just opens forum home page time to time or uses <em>search.php?search_id=unreadposts</em> and clicks on the unread post icons.</p>
<p>And lastly, our forum is publicly available, but &#8230; it is closed with .htaccess and we switched off registration. That is you not only need to pass .htaccess but also have an account to see posts. Are we a bit paranoid about it? Maybe.  For now it is not hard for me to switch on board registration, register a client account as if he had registered himself, switch off board registration, activate a new account and explain to a client how to use the forums, mail URL, .htaccess and account login details.</p>
<p>When it <a href="http://www.deepshiftlabs.com/dev_blog/?p=634&#038;lang=en-us#forum_en" target="_blank">became clear</a>, that dotProject&#8217;s forum does not suit us anymore, we decided not to fix and adjust it. We started using phpBB, despite of the fact that dotProject&#8217;s forum already contained lots of posts (to be precise 8247 posts by the time we swithed to phpBB). We had to visit it quite often at the beginning but with time more and more posts were created in phpBB and dotProject&#8217;s forum was visited less and less. Now very rarely. Our team is distributed &#8211; USA, Australia and Ukraine, so a forum for us is a must have. One may think that it is not needed if you are all in the same room and can just talk. It will be interesting to find out about your approach.</p>
<p>This is why we advise you not to look for an optimal project management system (with decent forum component) and use what fits best for handling projects, tasks, time tracking and communicate in a specialised forum.</p>
<p>In a list we announced <a href="http://www.deepshiftlabs.com/dev_blog/?p=925&amp;lang=en-us" target="_blank">here</a> we have to write about PHP Under Control, I think Dmitry will be able to carve out some time and write about it next time.<br />
</p>
<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/LCYD2nCeyI4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=928&amp;lang=en-us</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=928&amp;lang=en-us</feedburner:origLink></item>
		<item>
		<title>How do we use Review Board</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/XqQ6a2pgEEo/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=930&amp;lang=en-us#comments</comments>
		<pubDate>Thu, 27 Oct 2011 06:37:01 +0000</pubDate>
		<dc:creator>Igor Kryltsov</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=930</guid>
		<description><![CDATA[

We are quite conservative in the use of a version control system. Three years ago, Vadym had convinced us to start using SVN instead of CVS. At the same time Nerrvana came into our lives and we wanted to try some new systems that we thought would improve the process of its development. So we [...]]]></description>
			<content:encoded><![CDATA[<div style="float: left;"><a href="http://www.phpbb.com/" target="_blank"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_logo.png" alt="How do we use Review Board" width="141" height="128" /></a></div>
<p><br />
We are quite conservative in the use of a version control system. Three years ago, Vadym had convinced us to start using SVN instead of CVS. At the same time <a href="http://www.nerrvana.com" target="_blank">Nerrvana</a> came into our lives and we wanted to try some new systems that we thought would improve the process of its development. So we eventually adopted PHP Under Control (PUC) and Review Board (RB).</p>
<p>Today we will talk about RB. We use RB in the post commit mode. In this mode code is first committed to the SVN repository, and then later SVN RB hook* picks it up, adds to the RB which in turn sends letters to all the participants signed on changes in this SVN repository.</p>
<p>There is another mode &#8211; pre-commit. More information can be found in the RB <a href="http://www.reviewboard.org/docs/manual/dev/users/getting-started/workflow/" target="_blank">documentation</a>. <a href="http://www.reviewboard.org/docs/manual/dev/users/review-requests/creating/#creating-review-requests" target="_blank">This</a> mode requires that the review request is created by hand. We thought it would be much easier to get it to do SVN. What if the errors will slip into the repository? They get there anyway <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  But the requests are generated automatically, and errors in the code can be fixed in the next commit.<br />
<span id="more-930"></span><br />
We have several repositories for different projects. RB makes it easy to customize who will get review requests. First, if there is no hook in the repository, there will be no review requests. Second, as shown in the screenshot below, within the administrative interface RB has a page that allows you to fine tune who gets notified with regular expressions.</p>
<p><img class="aligncenter" title="Review Board administrative interface" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_7.png" alt="" /></p>
<p style="text-align: center;">Fig. 1 Fine tuning who gets what in admin UI</p>
<p>How does it work for us?</p>
<p>Let’s take a project were three of us are involved &#8211; me, Dmitry and Alexander. For example I did a commit. Immediately after a commit, a review request appears in RB with Open status. All three of us are working on this project will get a message about a new review request.</p>
<p><a title="Click to enlarge" href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_1.png" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Review Board Dashboard" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_1_720.png" alt="click to enlarge" /></a></p>
<p style="text-align: center;">Fig. 2 Dashboard<br />
<em>(click to enlarge)</em></p>
<p>Using the link inside an email Dmitry and Alex can open diff, and see if everything is all right. We agreed that if all goes well, we review by setting the flag &#8220;Ship it!&#8221; You can also write a comment like &#8220;OMG – so much work, congrats on finishing&#8221; or &#8220;Have no idea what you did, life will prove if you are right. The first three lines &#8211; OK&#8221;.</p>
<p><a title="Click to enlarge" href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_2.png" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Review Board review request" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_2_720.png" alt="click to enlarge" /></a></p>
<p style="text-align: center;">Fig. 3 Review Request<br />
<em>(click to enlarge)</em></p>
<p>Let’s say, Alex looked at my commit in RB and is happy with everything. He marks the review as &#8220;Ship it&#8221; straight away. However Dmitry has some comments. He writes about them, and leaves the review as is (not marking it &#8220;Ship it&#8221;). All of us will get an email from RB with Dmitry’s comments. I am reading it, looking at the code and writing a response inside Review Board precisely around line 214 where Dmitry commented. For example &#8211; &#8216;Thank you, my terrible mistake – do not tell my mum please&#8217;.</p>
<p><img class="aligncenter" title="Review Board Ship It" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_3.png" alt="" /></p>
<p style="text-align: center;">Fig. 4 Ship it</p>
<p>Then I correct an error in the code and make a new commit with the commit message containing a link to this review. This creates yet another review request, but by looking at its commit message, containing a reference to RB review, it becomes clear to all that this commit fixes up a problem as a result of previous review. After that, Dmitry with a clear conscience, marks both reviews (one where problem was found and one where it was corrected) as the &#8220;Ship it&#8221;. It is quite possible there were no bugs in the code. In this case I write an explanation in the comments within the code directly in RB. Dmitry responds to it.</p>
<p><img class="aligncenter" title="Review Board menu" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_4.png" alt="" /></p>
<p style="text-align: center;">Fig. 5 Review menu</p>
<p>Alex can also join the discussion around that piece of code inside review request. In the end, Dmitry marks a review as &#8220;Ship it&#8221;, making it clear to me that it can be closed now. If I see two &#8220;Ship it&#8221; flags on my review request &#8211; this means both Dmitry and Alex are happy with a change, and close review request (Close-&gt; Submitted). It should be noted that with each new commit or each new comment RB sends mail to all of us with links. Here is the message sent by RB to me with a message from Alex that he looked at my changes and marked it “Ship it”.</p>
<p><img class="aligncenter" title="Review Board email" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_5.png" alt="" /></p>
<p style="text-align: center;">Fig. 6 Email notification</p>
<p>Once you leave a comment you&#8217;ll still get an email. An email about your own activity. We did not find how to configure the RB so that the author did not receive mail on their own activity and this is perhaps the only thing missing in RB. However, this does not affect our RB perception, which is very good overall.</p>
<p>In conclusion we are totally happy with Review Board and highly recommended it. If there are issues with the setup &#8211;  contact, we’ll help with what we can.</p>
<p>P.S. I almost forgot &#8211; <a href="http://reviews.reviewboard.org/groups/reviewboard/?show_submitted=1" target="_blank">here</a> is RB of RB development team. You may want to look at it.</p>
<p><img class="aligncenter" title="Review Board inline comments" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/10/rb_comments.png" alt="" /></p>
<p style="text-align: center;">Fig. 7 Inline comments on RB site</p>
<hr />
<p>* &#8211; about hooks<br />
We took <a href="http://reviews.reviewboard.org/r/589/" target="_blank">the hook</a> for SVN. Vadym changed it by commenting out things we do not need and connected to SVN. You can read more about the hook for SVN <a href="http://mikewest.org/2006/06/subversion-post-commit-hooks-101" target="_blank">here</a>.</p>
<p>Here&#8217;s the code we use:</p>

<div class="wp_codebox_msgheader wp_codebox_hide"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p930code7'); return false;">View Code</a> TEXT</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p9307"><td class="code" id="p930code7"><pre class="text" style="font-family:monospace;">#!/bin/bash
REPOS=&quot;$1&quot;
REV=&quot;$2&quot;
cd ~apache
/usr/bin/python /var/svn/hooks/reviewboard-post-commit-hook.py &quot;$REPOS&quot; &quot;$REV&quot; &amp;amp;&amp;gt;/dev/null || exit 1</pre></td></tr></table></div>

<p>This is an actual file reviewboard-post-commit-hook.py we use:</p>

<div class="wp_codebox_msgheader wp_codebox_hide"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p930code8'); return false;">View Code</a> PYTHON</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p9308"><td class="code" id="p930code8"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># reviewboard-post-commit-hook</span>
<span style="color: #808080; font-style: italic;"># This script should be invoked from the subversion post-commit hook like this:</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># REPOS=&quot;$1&quot;</span>
<span style="color: #808080; font-style: italic;"># REV=&quot;$2&quot;</span>
<span style="color: #808080; font-style: italic;"># /usr/bin/python /some/path/reviewboard-post-commit-hook.py &quot;$REPOS&quot; &quot;$REV&quot; || exit 1</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># Searches the commit message for text in the form of:</span>
<span style="color: #808080; font-style: italic;">#   publish review - publishes a review request</span>
<span style="color: #808080; font-style: italic;">#   draft review - creates a draft review request</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># The space before 'review' may be ommitted.</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># The log message is interpreted for review request parameters:</span>
<span style="color: #808080; font-style: italic;">#    summary = up to first period+space, first new-line, or 250 chars</span>
<span style="color: #808080; font-style: italic;">#    description = entire log message</span>
<span style="color: #808080; font-style: italic;">#    existing review updated if log message includes 'update review:[0-9]+'</span>
<span style="color: #808080; font-style: italic;">#    bugs added to review if log message includes commands as defined in</span>
<span style="color: #808080; font-style: italic;">#      supported_ticket_cmds</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># By default, the review request is created out of a diff between the current</span>
<span style="color: #808080; font-style: italic;"># revision (M) and the previous revision (M-1).</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># To create a diff that spans multiple revisions, include</span>
<span style="color: #808080; font-style: italic;"># 'after revision:[0-9]+' in the log message.</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># To limit the diff to changes in a certain path (e.g. a branch), include</span>
<span style="color: #808080; font-style: italic;"># 'base path:&quot;</span>
<span style="color: #483d8b;">&quot;' in the log message.  The path must be relative to
# the root of the repository and be surrounded by single or double quotes.
#
# An example commit message is:
#
#    Changed blah and foo to do this or that.  Publish review ticket:1
#      update review:2 after revision:3 base path:'internal/trunk/style'.
#
# This would update the existing review 2 with a diff of changes to files under
# the style directory between this commit and revision 3.  It would place
# the entire log message in the review summary and description, and put
# bug id 1 in the bugs field.
#
# This script may only be run from outside a working copy.
#
&nbsp;
#
# User configurable variables
#
&nbsp;
# Path to post-review script
POSTREVIEW_PATH = &quot;</span>/usr/bin/<span style="color: #483d8b;">&quot;
# Username and password for Review Board user that will be connecting
# to create all review requests.  This user must have 'submit as'
# privileges, since it will submit requests in the name of svn committers.
USERNAME = 'XXXXX'
PASSWORD = 'XXXXXXXXXXX'
&nbsp;
# If true, runs post-review in debug mode and outputs its diff
DEBUG = False
&nbsp;
#
# end user configurable variables
#
&nbsp;
import sys
import os
import subprocess
import re
import svn.fs
import svn.core
import svn.repos
&nbsp;
# list of trac commands from trac-post-commit-hook.py.
# numbers following these commands will be added to the bugs
# field of the review request.
# supported_ticket_cmds = {'review':         '_cmdReview',
#                          'publishreview':  '_cmdReview',
#                          'publish review': '_cmdReview',
#                          'draftreview':    '_cmdReview',
#                          'draft review':   '_cmdReview'}
#
# ticket_prefix = '(?:#|(?:ticket|issue|bug)[: ]?)'
# ticket_reference = ticket_prefix + '[0-9]+'
# ticket_command = (r'(?P[A-Za-z]*).?'
#                   '(?P%s(?:(?:[, &amp;amp;]*|[ ]?and[ ]?)%s)*)' %
#                   (ticket_reference, ticket_reference))
&nbsp;
def execute(command, env=None, ignore_errors=False):
    &quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
    Utility function to execute a command <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #ff7700;font-weight:bold;">return</span> the output.
    <span style="color: black;">Derived</span> <span style="color: #ff7700;font-weight:bold;">from</span> Review Board<span style="color: #483d8b;">'s post-review script.
    &quot;&quot;&quot;
    if env:
        env.update(os.environ)
    else:
        env = os.environ
&nbsp;
    p = subprocess.Popen(command,
                         stdin = subprocess.PIPE,
                         stdout = subprocess.PIPE,
                         stderr = subprocess.STDOUT,
                         shell = False,
                         close_fds = sys.platform.startswith('</span>win<span style="color: #483d8b;">'),
                         universal_newlines = True,
                         env = env)
    data = p.stdout.read()
    rc = p.wait()
    if rc and not ignore_errors:
        sys.stderr.write('</span>Failed to execute command: <span style="color: #66cc66;">%</span>s\n<span style="color: #66cc66;">%</span>s\n<span style="color: #483d8b;">' % (command, data))
        sys.exit(1)
&nbsp;
    return data
&nbsp;
def main():
    if len(sys.argv) != 3:
        sys.stderr.write('</span>Usage: <span style="color: #66cc66;">%</span>s  \n<span style="color: #483d8b;">' % sys.argv[0])
        sys.exit(1)
&nbsp;
    repos = sys.argv[1]
    reposname = os.path.basename(repos)
    rev = sys.argv[2]
&nbsp;
    # verify that rev parameter is an int
    try:
        int(rev)
    except ValueError:
        sys.stderr.write(&quot;Parameter  must be an int, was given %s<span style="color: #000099; font-weight: bold;">\n</span>&quot; % rev)
        sys.exit(1)
&nbsp;
    # get the svn file system object
    fs_ptr = svn.repos.svn_repos_fs(svn.repos.svn_repos_open(
            svn.core.svn_path_canonicalize(repos)))
&nbsp;
    # get the log message
    log = svn.fs.svn_fs_revision_prop(fs_ptr, int(rev),
                                    svn.core.SVN_PROP_REVISION_LOG)
&nbsp;
    # error if log message is blank
    if len(log.strip()) &amp;lt; 1:
        sys.stderr.write(&quot;Log message is empty, no review request created<span style="color: #000099; font-weight: bold;">\n</span>&quot;)
        sys.exit(1)
&nbsp;
    # get the author
    author = svn.fs.svn_fs_revision_prop(fs_ptr, int(rev),
                                       svn.core.SVN_PROP_REVISION_AUTHOR)
&nbsp;
    # error if author is blank
    if len(author.strip()) &amp;lt; 1:
        sys.stderr.write(&quot;Author is blank, no review request created<span style="color: #000099; font-weight: bold;">\n</span>&quot;)
        sys.exit(1)
&nbsp;
    # check whether to create a review, based on presence of word
    # '</span>review<span style="color: #483d8b;">' with prefix
    # review = r'</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">?</span>:publish|draft<span style="color: black;">&#41;</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">?</span>: <span style="color: black;">&#41;</span><span style="color: #66cc66;">?</span>review<span style="color: #483d8b;">'
    # if not re.search(review, log, re.M | re.I):
    #     print '</span>No review requested<span style="color: #483d8b;">'
    #     sys.exit(0)
&nbsp;
    # check for update to existing review
    # m = re.search(r'</span>update<span style="color: black;">&#40;</span><span style="color: #66cc66;">?</span>: <span style="color: black;">&#41;</span><span style="color: #66cc66;">?</span>review:<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>-<span style="color: #ff4500;">9</span><span style="color: black;">&#93;</span>+<span style="color: black;">&#41;</span><span style="color: #483d8b;">', log, re.M | re.I)
    # if m:
    #     reviewid = '</span>--review-request-<span style="color: #008000;">id</span>=<span style="color: #483d8b;">' + m.group(1)
    # else:
    #     reviewid = '</span><span style="color: #483d8b;">'
&nbsp;
    # check whether to publish or leave review as draft
    # if re.search(r'</span>draft<span style="color: black;">&#40;</span><span style="color: #66cc66;">?</span>: <span style="color: black;">&#41;</span><span style="color: #66cc66;">?</span>review<span style="color: #483d8b;">', log, re.M | re.I):
    #     publish = '</span><span style="color: #483d8b;">'
    # else:
    publish = '</span>-p<span style="color: #483d8b;">'
&nbsp;
    # get previous revision number -- either 1 prior, or
    # user-specified number
    #m = re.search(r'</span>after<span style="color: black;">&#40;</span><span style="color: #66cc66;">?</span>: <span style="color: black;">&#41;</span><span style="color: #66cc66;">?</span>revision:<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>-<span style="color: #ff4500;">9</span><span style="color: black;">&#93;</span>+<span style="color: black;">&#41;</span><span style="color: #483d8b;">', log, re.M | re.I)
    #if m:
    #    prevrev = m.group(1)
    #else:
    prevrev = int(rev) - 1
&nbsp;
    # check for an explicitly-provided base path (must be contained
    # within quotes)
    #m = re.search(r'</span>base <span style="color: #66cc66;">?</span>path:<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>\<span style="color: #483d8b;">'&quot;][^<span style="color: #000099; font-weight: bold;">\'</span>&quot;]+[<span style="color: #000099; font-weight: bold;">\'</span>&quot;])'</span>, log, <span style="color: #dc143c;">re</span>.<span style="color: black;">M</span> | <span style="color: #dc143c;">re</span>.<span style="color: black;">I</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;">#if m:</span>
    <span style="color: #808080; font-style: italic;">#    base_path = m.group(1)</span>
    <span style="color: #808080; font-style: italic;">#else:</span>
    <span style="color: #808080; font-style: italic;">#    base_path = ''</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># get bug numbers referenced in this log message</span>
    <span style="color: #808080; font-style: italic;"># ticket_command_re = re.compile(ticket_command)</span>
    <span style="color: #808080; font-style: italic;"># ticket_re = re.compile(ticket_prefix + '([0-9]+)')</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># ticket_ids = []</span>
    <span style="color: #808080; font-style: italic;"># ticket_cmd_groups = ticket_command_re.findall(log)</span>
    <span style="color: #808080; font-style: italic;"># for cmd, tkts in ticket_cmd_groups:</span>
    <span style="color: #808080; font-style: italic;">#     funcname = supported_ticket_cmds.get(cmd.lower(), '')</span>
    <span style="color: #808080; font-style: italic;">#     if funcname:</span>
    <span style="color: #808080; font-style: italic;">#         for tkt_id in ticket_re.findall(tkts):</span>
    <span style="color: #808080; font-style: italic;">#             ticket_ids.append(tkt_id)</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># if ticket_ids:</span>
    <span style="color: #808080; font-style: italic;">#     bugs = '--bugs-closed=' + ','.join(ticket_ids)</span>
    <span style="color: #808080; font-style: italic;"># else:</span>
    <span style="color: #808080; font-style: italic;">#     bugs = ''</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># summary is log up to first period+space / first new line / first 250 chars</span>
    <span style="color: #808080; font-style: italic;"># (whichever comes first)</span>
    summary = <span style="color: #483d8b;">'--summary='</span> + log<span style="color: black;">&#91;</span>:<span style="color: #ff4500;">250</span><span style="color: black;">&#93;</span>.<span style="color: black;">splitlines</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'. '</span><span style="color: black;">&#41;</span>.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># other parameters for postreview</span>
    <span style="color: #808080; font-style: italic;"># repository_url  = '--repository-url=file://' + repos</span>
    repository_url  = <span style="color: #483d8b;">'--repository-url=http://XXXXXXXXXXX.com/svn/'</span> + reposname
    password        = <span style="color: #483d8b;">'--password='</span> + PASSWORD
    username        = <span style="color: #483d8b;">'--username='</span> + USERNAME
    description     = <span style="color: #483d8b;">&quot;--description=%s[%s]: %s&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>reposname, rev, log<span style="color: black;">&#41;</span>
    submitas        = <span style="color: #483d8b;">'--submit-as='</span> + author
    revision        = <span style="color: #483d8b;">'--revision-range=%s:%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>prevrev, rev<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># common arguments</span>
    args = <span style="color: black;">&#91;</span>repository_url, username, password, publish,
            submitas, revision<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># if not updating an existing review, add extra arguments</span>
    <span style="color: #808080; font-style: italic;">#if len(reviewid) == 0:</span>
    args += <span style="color: black;">&#91;</span>summary, description<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> DEBUG:
        args += <span style="color: black;">&#91;</span><span style="color: #483d8b;">'-d'</span>, <span style="color: #483d8b;">'--output-diff'</span><span style="color: black;">&#93;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: black;">&#91;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>POSTREVIEW_PATH, <span style="color: #483d8b;">'post-review'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> + args
&nbsp;
    <span style="color: #808080; font-style: italic;"># Run Review Board post-review script</span>
    data = execute<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>POSTREVIEW_PATH, <span style="color: #483d8b;">'post-review'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> + args,
                   env = <span style="color: black;">&#123;</span><span style="color: #483d8b;">'LANG'</span>: <span style="color: #483d8b;">'en_US.UTF-8'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> DEBUG:
        <span style="color: #ff7700;font-weight:bold;">print</span> data
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>


<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/XqQ6a2pgEEo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=930&amp;lang=en-us</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=930&amp;lang=en-us</feedburner:origLink></item>
		<item>
		<title>Own web analytics for startups – Part VII</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/E8qWql_0MLc/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=924&amp;lang=en-us#comments</comments>
		<pubDate>Mon, 29 Aug 2011 14:09:54 +0000</pubDate>
		<dc:creator>Igor Kryltsov</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=924</guid>
		<description><![CDATA[
Part VII &#8211; our plans changed, we start implementing it.
In our last post we promised to tell you about the integration of our product (Nerrvana) with our forum (phpBB), blog (WP) and marketing site. We also were planning to show how we added code to collect analytics info into each component. Our plans changed since.
We [...]]]></description>
			<content:encoded><![CDATA[<div style="float: left;"><a href="http://foto.delfi.ua/picture/425006/" target="_blank"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/01/web_analytics_thumb_7.png" alt="Своя веб-аналитика для стартапа – Часть VII" width="297" height="183" /></a></div>
<p><strong>Part VII &#8211; our plans changed, we start implementing it.</strong></p>
<p>In our <a href="http://www.deepshiftlabs.com/dev_blog/?p=658&amp;lang=en-us" target="_blank">last post</a> we promised to tell you about the integration of our product (Nerrvana) with our forum (phpBB), blog (WP) and marketing site. We also were planning to show how we added code to collect analytics info into each component. Our plans changed since.<br />
We decided to launch a beta version of our product without a forum, which takes the forum as well as Ideas and Answers out of our priorities list for now. We will add these parts during the beta testing period. But we need analytics anyway and it is time to start implementing it. Rephrasing &#8216;I sing what I see&#8217; into &#8216;I code what I sing&#8217; we start making it.</p>
<p>To heat up and tune we will complete a few tasks supporting our project.</p>
<p>1. Import GeoIP City database into PostgreSQL</p>
<p>We will need it to get visitors&#8217; location. If you read our previous posts this is not something we terribly want from web analytics. However it can be handy to figure out what our clients business hours are. It is to understand that city info can be very wrong. According to this database I am in Perth which is not true for me. I am in Sydney but my ISP is in Perth. Country info is more reliable.<br />
<span id="more-924"></span><br />
We take sources from <a href="http://www.maxmind.com/app/geolitecity" target="_blank">GeoLite City</a> and read <a href="http://www.siafoo.net/article/53" target="_blank">&#8216;Loading the GeoIP City database into PostgreSQL&#8217;</a>.</p>
<p>Create tables:</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p924code15'); return false;">View Code</a> SQL</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p92415"><td class="code" id="p924code15"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> locations
 <span style="color: #66cc66;">&#40;</span>
   id bigint <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
   country character<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
   region character<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
   city character varying<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">75</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
   postal_code character varying<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">15</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
   latitude numeric<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">6</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
   longitude numeric<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">7</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
  metro_code integer<span style="color: #66cc66;">,</span>
  area_code integer<span style="color: #66cc66;">,</span>
  CONSTRAINT locations_pkey <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> blocks
<span style="color: #66cc66;">&#40;</span>
  start_ip bigint <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  end_ip bigint <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  location_id bigint <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>
<span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>

<p>Execute:</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p924code16'); return false;">View Code</a> SQL</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p92416"><td class="code" id="p924code16"><pre class="sql" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">-- Data is in ISO-8859-15 format</span>
<span style="color: #993333; font-weight: bold;">SET</span> client_encoding <span style="color: #993333; font-weight: bold;">to</span> <span style="color: #ff0000;">&quot;ISO-8859-15&quot;</span>;</pre></td></tr></table></div>

<p>Put CSV files on C:\. Delete the first line containing copyright info and import them into database.</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p924code17'); return false;">View Code</a> SQL</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p92417"><td class="code" id="p924code17"><pre class="sql" style="font-family:monospace;">COPY locations <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>country<span style="color: #66cc66;">,</span>region<span style="color: #66cc66;">,</span>city<span style="color: #66cc66;">,</span>postal_code<span style="color: #66cc66;">,</span>latitude<span style="color: #66cc66;">,</span>longitude<span style="color: #66cc66;">,</span>metro_code<span style="color: #66cc66;">,</span>area_code<span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">'C:/GeoLiteCity-Location.csv'</span> <span style="color: #993333; font-weight: bold;">WITH</span> CSV HEADER;
&nbsp;
COPY blocks
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">'C:/GeoLiteCity-Blocks.csv'</span> <span style="color: #993333; font-weight: bold;">WITH</span> CSV HEADER;</pre></td></tr></table></div>

<p>We use Unix slash / here anyway even though we are on Windows.</p>
<p>2.  Enhance and improve log formats for Apache and ProFTPD</p>
<p>Before writing code we make a short stop and create own format for Apache logs based on standard &#8220;combined&#8221; type to make it more friendly for our home-grown web analytics. Here is a &#8220;combined&#8221; format:</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p924code18'); return false;">View Code</a> APACHE</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p92418"><td class="code" id="p924code18"><pre class="apache" style="font-family:monospace;"><span style="color: #00007f;">LogFormat</span> <span style="color: #7f007f;">&quot;%h %l %u %t <span style="color: #000099; font-weight: bold;">\&quot;</span>%r<span style="color: #000099; font-weight: bold;">\&quot;</span> %&amp;gt;s %b <span style="color: #000099; font-weight: bold;">\&quot;</span>%{Referer}i<span style="color: #000099; font-weight: bold;">\&quot;</span> <span style="color: #000099; font-weight: bold;">\&quot;</span>%{User-Agent}i<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span> combined</pre></td></tr></table></div>

<p>we create own type:</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p924code19'); return false;">View Code</a> APACHE</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p92419"><td class="code" id="p924code19"><pre class="apache" style="font-family:monospace;"><span style="color: #00007f;">LogFormat</span> <span style="color: #7f007f;">&quot;%h %{%F %T}t  <span style="color: #000099; font-weight: bold;">\&quot;</span>%r<span style="color: #000099; font-weight: bold;">\&quot;</span> %&amp;gt;s %b <span style="color: #000099; font-weight: bold;">\&quot;</span>%{Referer}i<span style="color: #000099; font-weight: bold;">\&quot;</span> <span style="color: #000099; font-weight: bold;">\&quot;</span>%{User-Agent}i<span style="color: #000099; font-weight: bold;">\&quot;</span> <span style="color: #000099; font-weight: bold;">\</span>
visitor_id:%{visitor_id}n session_id:%{session_id}n user_id:%{user_id}n&quot;</span> nerrvana</pre></td></tr></table></div>

<p>Differences:</p>
<p>- dropped %l. Acording to <a href="http://httpd.apache.org/docs/current/mod/mod_log_config.html" target="_blank">docs</a> this is the &#8216;Remote logname (from identd, if supplied). This will return a dash unless mod_ident is present and IdentityCheck is set On. Value always empty and useless for us.</p>
<p>- dropped %u. Also always empty.</p>
<p>- changed date/time format from standard  [24/Jul/2011:08:49:07 +0000] to 2011-07-24 08:49:07</p>
<p>- added session_id:%{session_id}n user_id:%{user_id}n. We wrote about it <a href="http://www.deepshiftlabs.com/dev_blog/?p=658&amp;lang=en-us" target="_blank">before</a>. These values will be empty in logs for now as we haven&#8217;t modified marketing site and Nerrvana UI pages yet. But this will not stop us &#8211; we have many other things to do before we will start looking into these values. For now we will add dummy values when we will parse logs to database tables.</p>
<p>Now about a few specific things we have to deal with.</p>
<p>First one is an FTP server (<a href="http://www.proftpd.org/" target="_blank">ProFTPD</a>) which is part of our Nerrvana. It allows to upload Selenium tests and download results. Nerrvana can work with multiple FTP servers. We built it this way to make the system more flexible and potentially distributed. Each machine runs FTP server (currently we have only one) and also runs Apache with authorization overlooking ftp folders. It allows us to provide HTTPS access from UI to test results. Since FTP servers are running on different virtual or physical machines their Apache&#8217;s logs are located there too. When a user clicks a link to browse test results we loose him in Nerrvana logs. To solve this problem we use redirect pages which leave this info in Nerrvana logs and redirects the user to a page he wanted to see.</p>
<p>Second thing is also related to having a FTP server as a part of our system. Normal workflow we expect after registration &#8211; create a place to load files we call Space, connect to it with FTP client and load Selenium tests, create schedule and run tests. In our analytics we want to know how real workflow deviates from ideal one. It&#8217;s one thing if a client created his Space but never uploaded files, another &#8211; when he loaded and deleted files without making an attempt to launch tests. We need to know this to pro-actively help a particular client before he abandons our service or to see a wider problem many clients face. So we are going to parse the second type of log &#8211; <a href="http://www.castaglia.org/proftpd/doc/xferlog.html" target="_blank">xferlog</a>.</p>
<p>It looks like this:</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p924code20'); return false;">View Code</a> TEXT</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p92420"><td class="code" id="p924code20"><pre class="text" style="font-family:monospace;">Tue May 31 16:08:17 2011 0 ::ffff:192.168.1.254 303 /var/lib/trillium/ftproot/demo433/sf_tests/_files/build/class/com/deepshiftlabs/sf_tests/SftestException.class b _ i r demo433 ftp 0 * c</pre></td></tr></table></div>

<p>From manual:</p>
<p>current-time   transfer-time   remote-host   file-size   filename   transfer-type   special-action-flag   direction   access-mode   username   service-name   authentication-method   authenticated-user-id  completion-status</p>
<p>Everything is pretty straightforward. Client  demo433  on 31st of May at 16:08:17 loaded (i) file SftestException.class. We do not create a security tracking system and this is why we will store bare minimum of info to keep client&#8217;s privacy. With FTP we only need to know the sort of activity (uploaded, downloaded, deleted). If files are constantly downloaded, deleted, uploaded &#8211; most likely files are getting edited in ftp client. We need to rush with enabling ssh access for client&#8217;s accounts. If we will store just file extensions we will be able to see preferences of a particular client on one side and have stats what languages are used by free/paid/heavy/light Nerrvana users.</p>
<p>Analytics? Yes. Web analytics? Don&#8217;t know &#8211; we craft analytics of a special kind not blindly following fundamentals of this art but strongly adhering to common sense, customer care and commitment to excellence.</p>
<p>On this optimistic note I will finish this post. Next post &#8211; log parsing and storage, crawler traffic recognition, exceptions in logs to ignore, extracting key phrases from search engine referrers. Did I miss something? E-mail &#8211; help me out.<br />
</p>
<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/E8qWql_0MLc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=924&amp;lang=en-us</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=924&amp;lang=en-us</feedburner:origLink></item>
		<item>
		<title>How do we use Kayako – Part I</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/RwKD2_g967s/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=1398&amp;lang=en-us#comments</comments>
		<pubDate>Mon, 22 Aug 2011 11:42:01 +0000</pubDate>
		<dc:creator>Igor Kryltsov</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=1398</guid>
		<description><![CDATA[
This post lists our requirements for a support system and will be followed up (in our next post) by configuration instructions implementing them in a system of our choice &#8211; Kayako.
You may ask us &#8216;Why Kayako?&#8217; We tried some other systems &#8211; open source OTRS, OSTicket and commercial HelpSpot. Below you can find some reasons [...]]]></description>
			<content:encoded><![CDATA[<div style="float: left;"><a href="http://www.kayako.com/" target="_blank"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/08/kayako.png" alt="How do we use Kayako - Part I" width="177" height="154" /></a></div>
<p>This post lists our requirements for a support system and will be followed up (in our next post) by configuration instructions implementing them in a system of our choice &#8211; <a href="http://www.kayako.com/" target="_blank">Kayako</a>.<br />
You may ask us &#8216;Why Kayako?&#8217; We tried some other systems &#8211; open source OTRS, OSTicket and commercial HelpSpot. Below you can find some reasons why these systems were rejected by us.</p>
<p>HelpSpot<br />
- no prebuilt list of customers<br />
- sharing is global and is not per portal at this time.  So we can not turn on sharing (seeing all tickets for a company) for a client and turn it off for Nerrvana.<br />
OTRS<br />
- did not like UI<br />
- too complex<br />
- no portals<br />
OSTicket<br />
- no sharing. Each user can see only their own tickets<br />
- no time tracking<br />
- no portals</p>
<p>What are our requirements?<br />
<span id="more-1398"></span><br />
1. We have clients (companies) we design web applications for and we need a support system. Using emails for support is not a viable option for us anymore. We deal with helpdesk support staff in these companies when we talk about support. Do they raise a ticket using their own support system in principle? How well their support department is managed? Do they require to create a ticket or search their internal system before escalating something to us? We do not know. But nobody can stop us from optimising the time we spent on support.</p>
<p>We more often have situations when Brad asks us exactly the same question we answered for Joy a week ago. Or even when Joy asks us about particular problem X, which Brad already raised and she has no clue that some replies already have been sent to Brad. We are doing our best to pick up common questions and move them to &#8216;How To&#8217;, a forum clients can access but despite of it lots of time is spent to find all the emails we sent to Brad and send it to Joy. It is often not enough to find the last email as it might not contain the whole story and if you do so you will have more questions from Joy anyway. Support system on our side with shared access to tickets for client&#8217;s staff allows us to find a ticket and forward it or point to a &#8216;How To&#8217; article and close it.</p>
<p>In some projects an active development phase is completed and support work kicks in as a primary activity. We fix bugs, complete some change requests and answer questions. When you actively develop and support using email it is too hard to figure out how much time goes to support. Very important to know, it is (in yoda voice).</p>
<p>I do not think I will surprise you by telling you a fact that development speed is directly related to how much goes to support. At least in a small team like ours. If we code fast there is no time to maintain documentation up-to-date which causes more questions and more time for support. In this situation we need to figure out ourselves how much support the system we designed requires and what are the best terms for us to negotiate for a future support &amp; maintenance agreement. It could be a fixed amount per month, or by hours actually spent or a combination of them. X amount a month for 20 hours of support with Y amount per hour for anything above 20 hours. So we continue to use <a href="http://www.deepshiftlabs.com/dev_blog/?p=927&amp;lang=en-us" target="_blank">dotProject</a> as an internal project management system, phpBB as a place to discuss projects from dotProject as well as a place to discuss projects with clients and replace support by email with Kayako.</p>
<p>2. We created a system (<a href="http://angel.co/nerrvana-1" target="_blank">Nerrvana</a>) we are going to launch this year and we would like to have a decent support system accompanying it. Our clients do not even need to interact with the support system UI, but we will. It will allow us as developers to be organised and solve clients&#8217; problems quickly.</p>
<p>Now let&#8217;s go from background info into details.</p>
<p>With point 1 (clients&#8217; work) &#8211; all is simple and clear. We create in Kayako companies-clients and pre-create all staff members from their helpdesk departments. If changes will need to be made i.e. new person started &#8211; head of support will request us using Kayako as well. Kayako has an option to make a company shared which means all users can see and update all company tickets. They log in to custom portal for example http://support.deepshiftlabs.com/index.php?/client_1_company_name and see and update all tickets. It is by company, not a global setting. This is exactly what we want for our clients. Joy will see what we responded to Brad if she works on his ticket. One Kayako install allows you to have many portals and email queues associated with them. You create email, associate it with a queue and create a portal. If you have two clients you will have:</p>
<p>Email client1@support.deepshiftlabs.com and portal http://support.deepshiftlabs.com/index.php?/client1<br />
Email client2@support.deepshiftlabs.com and portal http://support.deepshiftlabs.com/index.php?/client2</p>
<p>Tickets can be created from inside the portal or by simply emailing it to an associated email. New tickets created either way generate an auto-response containing a ticket ID allocated. By keeping it in subject you will update the ticket by simply replying to it.</p>
<p>Let&#8217;s look at requirements for point 2 (own product). Our portal will be on http://support.deepshiftlabs.com/index.php?/nerrvana. We read <a href="http://blog.asmartbear.com/one-email.html" target="_blank&quot;">&#8216;Why your company should have a single email address&#8217;</a> and think it makes sense first of all for our clients and decided to go this way. Therefore all places where we will provide email including support will use contact@nerrvana.com. Each and every email will go to Kayako queue for processing. We are going to send only one auto-generated email (may be only while we are sleeping and can&#8217;t reply quickly) as it is important, from our point of view, for a sender to know that their email was delivered. Besides it will be from contact@nerrvana.com and it won&#8217;t be &#8216;please do not reply&#8217; but a &#8216;please feel free to reply&#8217; email. If Kayako does not have sender&#8217;s email in database it will create a new account automatically. So an important difference in Kayako configuration for our product will be an instruction to accept all incoming mail for contact@nerrvana.com. In point 1 (for our contract work with clients) we accept requests only from pre-created by us emails.</p>
<p>The second major difference in configuring Kayako for own product will be enabling and using Kayako API. By using it we can allow our clients to raise support requests from inside our product UI. We can check if Kayako account already exists (we do not create accounts in Kayako when client registers), create it first if necessary and finally create a ticket. Kayako uses MySQL and we store account info in PostgreSQL. After ticket was created via API we can add a private note to it at the same time also via API. It will contain UI page reference where request was created and all supporting info. In our case this will be a test run execution where we can add necessary SQL statements and links to logs to speed up resolution for one of us who will work on this case.</p>
<p>We are also planning to create client&#8217;s profile page with information about registration date, account type, short history of activity, business hours and make it accessible from inside Kayako. This will allow us to see if a request came from a new user who can&#8217;t launch their first test (our system allows to launch Selenium tests on different platforms) or from a longtime client who might know our system as good as we do (well, almost). To summarize &#8211; all such handy info can be added to ticket via API from inside our application.</p>
<p>Finally a few notes about mail server configuration for Kayako. Kayako allows to use GMail account with enabled IMAP but we decided to use our own mail server (sendmail). This decision is based on our belief that Gmail uses multilevel Spam filtering approach and even if we will disable the Spam folder in GMail there is a chance that we won&#8217;t see some mail as it might be filtered out by low-level filters. For now we are not even planning to add Spam filter to it (normally SpamAssassin). We do want to have full control around what we receive especially since we use a single email for everything. Even if we will be forced to turn on the Spam filter on sendmail someone will glance over it before deleting emails. For the record, Kayako is also able to detect Spam and has a special folder inside UI.</p>
<p>Cheers for now. Kayako is installed and our next post will be about making it all work in Kayako (expect lots of screen shots).<br />
</p>
<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/RwKD2_g967s" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=1398&amp;lang=en-us</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=1398&amp;lang=en-us</feedburner:origLink></item>
		<item>
		<title>Naming chronicles</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/eWNRIl8RQf0/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=935&amp;lang=en-us#comments</comments>
		<pubDate>Thu, 12 May 2011 00:54:11 +0000</pubDate>
		<dc:creator>Igor Kryltsov</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=935</guid>
		<description><![CDATA[

After reading Jason Cohen&#8217;s post &#8220;Naming your startup: Settle down, it&#8217;s cool!&#8221;, I recalled previously read &#8220;How To Pick A Company Name: Tips From The Trenches&#8221; and &#8220;17 Mutable Suggestions For Naming A Startup&#8221;, and even a manual from Igor International. I still remember how we came up with the name. All discussions have been [...]]]></description>
			<content:encoded><![CDATA[
<div style="float: left;"><a href="http://ksju-nja.livejournal.com/2292.html" target="_blank"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/naming_chr_eng_tn.jpg" alt="Naming chronicles" width="300" height="199" /></a></div>
<p>After reading Jason Cohen&#8217;s post <a href="http://blog.asmartbear.com/naming-startup.html" target="_blank">&#8220;Naming your startup: Settle down, it&#8217;s cool!&#8221;</a>, I recalled previously read <a href="http://onstartups.com/tabid/3339/bid/12156/How-To-Pick-A-Company-Name-Tips-From-The-Trenches.aspx" target="_blank">&#8220;How To Pick A Company Name: Tips From The Trenches&#8221;</a> and <a href="http://onstartups.com/tabid/3339/bid/17702/17-Mutable-Suggestions-For-Naming-A-Startup.aspx" target="_blank">&#8220;17 Mutable Suggestions For Naming A Startup&#8221;</a>, and even a manual from <a href="http://www.igorinternational.com/process/naming-guide-product-company-names.php" target="_blank">Igor International</a>. I still remember how we came up with the name. All discussions have been recorded in our forum. Besides, I&#8217;ve never seen stories about inventing a name. And so was born the idea of this post.</p>
<p>Here is the (first?) naming chronicle. To ensure that you understand our conversations, I must say that English, for many of us, is the second, and for some &#8211; the third language. We were looking, of course, for an English name, so if some candidates may sound funny or have weird association in English, you&#8217;ll know that in Russian, they sound just great.<br />
<span id="more-935"></span><br />
Now a few words about the subject.</p>
<p>Deep Shift Labs &#8211; the name of our team, and therefore the product name consonant with the words &#8216;deep&#8217; or &#8217;shift&#8217; would have been good from our point of view.<br />
Selenium &#8211; our product uses <a href="http://seleniumhq.org/" target="_blank">Selenium</a>, and therefore the complete or partial (root or suffix of the word) presence of this word would also be not bad.<br />
Test-ing &#8211; our service performs automated functional tests, and therefore such a word can be present in the name.<br />
Cloud, Elastic, Virtual &#8211; the system creates a virtual environment consisting of 10 or 100, or &#8230; virtual machines.<br />
Bug, Error &#8211; it is clear that we are looking for &#8211; bugs, errors.</p>
<p>We had such, I would say, semantic environment before we started. Perhaps it is wise to start formulating it before you will start. We have not been writting it explicitly, but as you&#8217;ll see all the discussion swirled mostly around these words.</p>
<p>By the time this discussion around a name started in January 2010 we were already working on our system for a year and a half, and therefore we were searching for a name for the already running system. The system is created in our spare from contract work, time. From the very beginning we stuck with a consonant to Selenium name &#8211; Trillium. The word also contains the letter &#8216;T&#8217; from Testing, but, unfortunately, there <a href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/trillium.png" target="_blank ">are</a><sup>*</sup> too many people already using it. Besides, it is very close to a popular chat client <a href="http://www.trillian.im" target=" _blank ">Trillian</a> by Cerulean Studios. We started talking about a new name, as we were sure that we can come up with a better name with a free domain. With every moment of inspiration, we were generating and discussing names over and over again. Some of these dialogues are listed below with a small author&#8217;s corrections</p>
<p>The discussion participants:<br />
<a href="http://www.linkedin.com/in/igorkryltsov" target="_blank">Igor</a><br />
<a href="http://ua.linkedin.com/pub/yakubovskiy-dmitriy/10/b34/4ba" target="_blank">Dmitriy</a><br />
<a href="http://ua.linkedin.com/pub/alexander-savchenko/3/6b3/516" target="_blank">Alex</a><br />
<a href="http://www.linkedin.com/in/olegkiselev" target="_blank">Oleg</a> &#8211; advises us when he is interested in our questions and they intersect with his knowledge and experience. We consider him as an adviser and therefore ask questions … not so often  <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div style="float: right;"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/naming_chr_4.jpg" alt="" width="218" height="136" /></div>
<p><strong>Mon Jan 11, 2010 11:14 am &#8211; Igor</strong></p>
<p>Trillium &#8211; current name</p>
<p>ShiftOS or ShiftOs or Shiftos<br />
ShiftOZ or ShiftOz or Shiftoz &#8211; Australia &#8211; <a href="http://in.answers.yahoo.com/question/index?qid=20080731014435AAZHowE" target="_blank">Oz</a><br />
Shiftoid &#8211; imaginary<br />
Selenoid &#8211; imaginary<br />
Selenius &#8211; imaginary</p>
<p>Selen &#8211; imaginary<br />
Selenite &#8211; &#8220;contains no significant selenium; the similarity of names comes from both substances being named from the Ancient Greek word for the Moon.&#8221;<br />
Selenide &#8211; &#8220;chemical compound in which selenium serves as an anion&#8221;<br />
Selenosis &#8211; Selenium poisoning<br />
Selenious &#8211; containing Selenium</p>
<p>Gridder &#8211; a player</p>
<p>Found and immediately discarded (a word &#8216;test&#8217;, turned out to be quite dangerous):<br />
Testaceous &#8211; having a hard shell or shell-like outer covering<br />
Testa &#8211; the protective outer covering of a seed.<br />
Testee &#8211; one who takes or has taken a test.<br />
Testoid &#8211; any substance, as testosterone or androsterone, that promotes male characteristics.<br />
Testis &#8211; an organ which produces sperm.</p>
<p><strong>Tue Jan 19, 2010 9:08 pm &#8211; Dmitriy</strong></p>
<p><span class="forum_notes">In a parallel discussion topic we were talking about character/logo, where pretty soon we agreed to use a chameleon. It is catching bugs (even at a great distance, like our system), changes colour and looks in all directions. Therefore, further you will come across words that intersect with the word &#8216;chameleon&#8217; (author’s note).</span></p>
<p>Chameleon is a cool personage too.  You have everything &#8211; nice tail, and unique tongue, eats bugs, and the changes colours.</p>
<p><strong>Mon Jan 18, 2010 2:19 pm &#8211; Igor</strong></p>
<p>Two sounding like chameleon + selenium names:</p>
<p>Seleon – imaginary<br />
<a href="http://en.wiktionary.org/wiki/selion" target="_blank">Selion</a></p>
<p><strong>Wed Jan 20, 2010 11:45 am &#8211; Igor</strong></p>
<p><span class="forum_quote"> Dmitriy: &#8220;Chameleon is a cool personage too.  You have everything &#8211; nice tail, and unique tongue, eats bugs, and the changes colours.&#8221;</span></p>
<p>Additionally a chameleon is a much simpler character to create funny situations around. Another perfect match is an ability to &#8217;stretch&#8217; his tongue &#8211; we also can stretch and create more VMs as well as to &#8216;change colour&#8217; &#8211; we can test Windows IE8 and Firefox on Linux. These are very nice parallels.</p>
<p>Today on the morning train I was thinking that we need to sort of align our character/logo concept with the product name and also invent a motto.</p>
<p>What is the essence of our system? We are a &#8220;Selenium cloud&#8221;. Cloud means an elastic, stretchable environment which can be used on demand (when needed). Amazon calls its service Elastic Computing Cloud, Oleg&#8217;s business is called Parascale<sup>**</sup> which uses &#8217;scale&#8217; or &#8217;scalable&#8217;. I also used word &#8216;valium&#8217; thinking of combining it with &#8217;selenium&#8217; and motto &#8216;Stress free Selenium testing&#8217; or something along these lines but after passing several stations (remember I was on a train), I realised that being in fact stress-free it does not reflect the root purpose of our service, which is from my point of view &#8211; scalability Selenium way.</p>
<p>After I realised this I started with words which are:<br />
Chameleon<br />
Selenium<br />
Elastic<br />
Valium<br />
Cloud</p>
<p>combining them into names:</p>
<div style="float: right;"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/naming_chr_3.jpg" alt="" width="347" height="212" /></div>
<p>–Valium&amp;Selenium<br />
Valenium (+)<br />
Selanium (+)</p>
<p>Selium &#8211; should not be here but &#8230;.<br />
–Scale&amp;Selenium<br />
Scalium<br />
Scanium</p>
<p>–Cloud&amp;Selenium<br />
Closelin (-)<br />
Closeus (-)<br />
Seclonium (-)<br />
Closenium (-)<br />
Clodium<br />
–Elastic&amp;Selenium<br />
Seltic<br />
Elanium (+)</p>
<p>The ones I liked, I marked with a plus and otherwise.<br />
Motto in all these names could be:<br />
- stress free Selenium cloud<br />
- elastic Selenium cloud<br />
- Selenium on a cloud</p>
<p>We can polish motto further. I am expecting this motto in big letters to be on top of the home page on the right side from logo and service name.</p>
<p><strong>Wed Jan 27, 2010 2:04 am &#8211; Alex</strong></p>
<p><span class="forum_quote"> Dmitriy: &#8220;Chameleon is a cool personage too.  You have everything &#8211; nice tail, and unique tongue, eats bugs, and the changes colours.&#8221;</span></p>
<p>Agree. Well, congratulations, on settling with a personage.</p>
<p><span class="forum_quote"> Igor:<br />
&#8220;–Valim+Selenium<br />
Valenium<br />
Selanium<br />
Selium – &#8211; should not be here but &#8230;.&#8221;<br />
</span></p>
<p>I associate Selanium and Elanium with drugs anyway, similar to &#8216;relanium&#8217;.  Selanium sounds better. Can I offer a couple of options? No? Well, I will anyway &#8211; Secleon (<span style="text-decoration: underline;">Se</span>lenium <span style="text-decoration: underline;">cl</span>oud chamel<span style="text-decoration: underline;">eon</span>), Scasecl (<span style="text-decoration: underline;">Sca</span>lable <span style="text-decoration: underline;">se</span>lenium <span style="text-decoration: underline;">cl</span>oud).</p>
<p><strong>Wed Jan 27, 2010 11:16 am &#8211; Igor</strong></p>
<p><span class="forum_quote"> Alex: &#8220;I associate Selanium and Elanium with drugs anyway, similar to &#8216;relanium&#8217;.&#8221;</span></p>
<p>Agree. Was carried away a little.</p>
<p><span class="forum_quote"> Alex: &#8220;Well, I will anyway &#8211; Secleon (Selenium cloud chameleon), Scasecl (Scalable selenium cloud).&#8221;</span></p>
<p>Your names account for everything but are hard to pronounce. Perhaps it makes sense to abandon attempts to include many things into a name as we can end up with something similar to <a href="http://www.ass-concerts.de/" target="_blank">A.S.S. Concerts</a>, and just call it, for example &#8211; Debugz. Sounds as debug and bugs and destroy bugs and move essence of it &#8211; Selenium cloud &#8211; into a slogan.</p>
<p><strong>Wed Jan 27, 2010 9:22 pm &#8211; Oleg</strong><br />
<span class="forum_notes">(we sent slogans and asked for an opinion &#8211; author&#8217;s note)</span></p>
<p>&#8220;selenium in the cloud&#8221; – sounds as a good description<br />
&#8220;stress-free selenium service in the cloud&#8221; – good slogan to me</p>
<p><strong>Sun Jan 31, 2010 11:33 am &#8211; Igor</strong><br />
Debugz – domain name taken.</p>
<p>Read here:<br />
http://en.wikipedia.org/wiki/Bazooka – domain name is obviously taken but I write anyway may be it will enlightens you with some deviations of it<br />
http://en.wikipedia.org/wiki/Chameleon – “and rapidly extrudable tongues” thinking of ‘eXtrudius’ or  ‘Extrudius’.</p>
<p>Since it is Selenium on demand – may be &#8216;<a href="http://en.wiktionary.org/wiki/demandus" target="_blank">Demandus</a>&#8216; or ‘Demandium’ or ‘Demanium’ with а Selen-ium suffix?</p>
<p><strong>Sun Jan 31, 2010 11:35 am &#8211; Igor</strong></p>
<p>Moving to <a href="http://dictionaries.travlang.com/EnglishEsperanto/dict.cgi?query=Chameleon&amp;max=50" target="_blank">Esperanto</a>.</p>
<p><strong>Mon Feb 01, 2010 10:29 pm &#8211; Igor</strong></p>
<p>From  Esperanto:<br />
eskali or eSkali – translated as ‘scale’.  It can be written in eBay style &#8211; small letter then capital). Registered trade mark is not found.<br />
insekto or inSekto – translated as ‘bug’. Word contains ‘Se’ which is Selenium from periodic table. Registered trade mark is not found.</p>
<p>Other words from Esperanto:<br />
demand – debito<br />
kill – mortigi<br />
cloud – nebuligi, nubo</p>
<p>Other non Esperanto names – trademarked and domains are taken:<br />
Bugster<br />
Bugbuster<br />
Buzzuka<br />
Buginator<br />
Buggle</p>
<p>Harry Potter theme:<br />
bugdemort.com – available but I am afraid of J. K. Rowling legal action <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
debugtor.com – was it dementor in a book? I like it. Do you?</p>
<p>debugius.com – available<br />
debugos.com –it is better than shiftos.com we were thinking of. Domain is available. selentos.com</p>
<p><strong>Tue Feb 02, 2010 1:39 am &#8211; Alex</strong></p>
<p>Discussed <span class="forum_notes">(with Dmitriy &#8211; author&#8217;s note)</span> and think that ‘eXtrudius’ or ‘Extrudius’ sound good.</p>
<p><span class="forum_quote"> Igor: &#8220;Demandus or Demandium or Demanium&#8221;</span></p>
<p>These ones smell demonology which is scary  <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Tue Feb 02, 2010 1:52 am &#8211; Alex</strong></p>
<p>We had a discussion tonight. Initial considerations &#8211; the trademark and domain name must be at least similar, ideally be the same. Of course this is not necessary condition, but it is highly desirable.</p>
<p><span class="forum_quote"> Igor:<br />
&#8220;debugtor.com<br />
debugius.com<br />
debugos.com&#8221;</span></p>
<p>The last two names seem to be ok (debugius.com, debugos.com), as previously discussed names &#8216;eXtrudius&#8217; or &#8216;Extrudius&#8217;. But none of them is an undisputed leader in each has some flaw to us. To make it easier to choose we also have prepared some names. All domains are free:</p>
<p>clinnium.com (1)<br />
bugspell.com (3)<br />
bugzcore.com (1)<br />
buzzless.com (1)<br />
deepium.com, deelium.com (3)<br />
deesbug.com (2)<br />
deesc.com (2)<br />
fireum.com (2)<br />
s-clo.com (1)<br />
sellenia.com (1)<br />
selenager.com (1)<br />
seekabug.com (1)</p>
<p>In brackets is the number of votes for each name, the favorites are easy to see <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   Let&#8217;s now based on the resulting list (three votes) will hold a final vote by selecting the three candidates and get the winner.</p>
<p><strong>Tue Feb 02, 2010 9:53 am &#8211; Oleg</strong></p>
<p>Except for &#8220;selentos&#8221; and &#8220;escali&#8221;, everything else sounds bad to me.<br />
You seem very focused on the -os and -us endings. Those aren&#8217;t terribly appealing.</p>
<p>Consider that many very popular web startups had weird names that had nothing to do with what they actually produced. If you want something that specifically focuses on what you do, what is it you think your business does? Selenium on demand testing. Selenium is derived from greek &#8220;selene&#8221; &#8212; moon. Is &#8220;moonwalk&#8221; taken?</p>
<p><span class="forum_quote"> Igor: &#8220;moonwalk.com is taken.&#8221;</span></p>
<p><strong>Tue Feb 02, 2010 12:50 pm &#8211; Igor</strong></p>
<p>Moon theme &#8211; Mooongle.com<br />
We can draw a chameleon behind a name and make two o&#8217;s his eyes. Pronounced as moongle. moongle.com is taken so I used triple &#8216;o&#8217;.</p>
<p>Also Moon in Latin is Lynaris and Lynaris.com is available but I like Mooongle more &#8211; sounds better and even like &#8220;you know who&#8221;.</p>
<p><strong>Tue Feb 02, 2010 2:31 pm &#8211; Igor</strong></p>
<p>We turn to the names of <a href="http://www.lowchensaustralia.com/names/abornames.htm" target="_blank">the Aborigines</a>.</p>
<p><strong>Tue Feb 02, 2010 8:00 pm &#8211; Dmitriy</strong></p>
<p><span class="forum_quote"> Oleg: &#8220;&#8230; many very popular web startups had weird names that had nothing to do with what they actually produced&#8221;</span></p>
<p>We discussed the idea of using some Russian nice-sounding word, such as <a href="http://en.wiktionary.org/wiki/%D0%BE%D0%B1%D0%BB%D0%B0%D0%BA%D0%BE" target="_blank">‘oblako’</a> (cloud).</p>
<p><span class="forum_quote"> Igor: &#8220;We turn to the names of the Aborigines &#8220;</span></p>
<p>Many nice words I have already heard <span class="forum_notes">(Dmitriy knows them as our clients branches are functioning in these towns &#8211; author&#8217;s note)</span>.  For instance arana – moon. By the way, I like the words aranda and armidale. Toowoomba also sounds mysterious.</p>
<p><span class="forum_quote"> Igor: &#8220;I like Mooongle more.&#8221;</span></p>
<p>The only thing I don’t like about Mooongle &#8211; association with Google. Or it is a good association?</p>
<p><strong>Tue Feb 02, 2010 8:46 pm &#8211; Igor</strong></p>
<p>Another brainstorming session on a train to work.</p>
<p>Domain names and mottos:<br />
nerrvana.com &#8211; finding errors in a pleasant way<br />
erranium.com &#8211; finding errors with stress free Selenium cloud<br />
erronium.com &#8211; same as above<br />
moonshu.com &#8211; moon and shoot &#8211; just and easy to say word related a bit<br />
nirvanium.com &#8211; free from suffering Selenium testing &#8211; this one is cool<br />
moonerr.com &#8211; find your web application errors with Selenium cloud (my kid said it sounds like <a href="http://en.wikipedia.org/wiki/Mooning" target="_blank">mooning</a> and we do not want it right?)</p>
<p>I like &#8216;moonshu&#8217;.</p>
<p>Dmitriy &#8211; I agree &#8211; trying to sound like Google is NOT good.</p>
<p>All domains are available. Let&#8217;s now not only offer options but state if domain is available or not. Many aborigines’ names (I posted earlier a link) appear to be taken.</p>
<p><strong>Tue Feb 02, 2010 8:59 pm – Dmitriy</strong></p>
<p><span class="forum_quote"> Igor: &#8220;I like &#8216;moonshu&#8217;.&#8221;</span></p>
<p>I think it is too Asian. I like nerrvana more.</p>
<p><span class="forum_quote"> Igor: &#8220;finding errors in a pleasant way&#8221;</span></p>
<p>Nice one <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Tue Feb 02, 2010 10:04 pm – Alex</strong></p>
<p><span class="forum_quote"> Dmitriy: &#8220;The only thing I don’t like about Mooongle &#8211; association with Google. Or it is a good association?&#8221;</span></p>
<p>In principle, any associations are good if name is easy to remember. The only bad thing it is hard to pronounce ‘ngl’ in Russian. Name is not bad apart from it.</p>
<p><strong>Tue Feb 02, 2010 10:13 pm &#8211; Alex</strong></p>
<p><span class="forum_quote"> Igor:<br />
&#8220;nerrvana.com &#8211; finding errors in a pleasant way<br />
nirvanium.com &#8211; free from suffering Selenium testing &#8211; this one is cool&#8221;</span></p>
<p>These two names are better than others to me. And if to choose from them I would take a second one. I do not like double letters, people will make mistakes and come to a different domain. If we would have in the same business with http://nervana.com/, it would be a clever move. By the way, they acted short sighted by not registering this domain.</p>
<p><strong>Wed Feb 03, 2010 10:39 am &#8211; Oleg</strong></p>
<p><span class="forum_quote"> Igor:<br />
&#8220;nerrvana.com<br />
erranium.com<br />
erronium.com<br />
moonshu.com<br />
nirvanium.com&#8221;</span></p>
<p>Honestly, this -um or -us ending doesn&#8217;t sit well with me, but it is just me. My preference, now that you pointed it to me, is to go with an aboriginal name.</p>
<p>Nirvanium sounds least offensive, but it is too close to <a href="http://www.nirvanix.com/" target="_blank">Nirvanix</a>. That&#8217;s grounds for customer confusion and a possibility Nirvanix getting upset and suing you &#8212; not that they&#8217;d have a case, but can you afford fighting it?</p>
<p>But it&#8217;s your company, not mine <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Wed Feb 03, 2010 12:28 pm &#8211; Igor</strong></p>
<p>Some companies have such nice for my heart  names &#8211; <a href="http://www.igorinternational.com/process/naming-guide-product-company-names.php" target="_blank">Igor International</a> while offering guidance on finding a name.</p>
<p>Turning to the Maori dictionary now <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>demand – tono. Any ideas around ‘tono’?<br />
‘Test’ and ‘try’ (<a href="http://www.ards.com.au/language/B.Lowe_Web_Dict.pdf" target="_blank">source</a>)<br />
birrku.com<br />
garrmun.com</p>
<p>In many languages a word ‘moon’ starts with ‘lyn…’<br />
lynerr.com<br />
lynderr.com</p>
<p>‘Minder’ is a good word and variations from it for your consideration:</p>
<p>moonminder.com – taken<br />
deminderr.com – demand, error, minder<br />
seederr.com – sees errors instead of you<br />
moterr.com – motor + error<br />
tuchkus.com – just another weird name in English but cloud in Russian<br />
lynabite.com – moon + bite<br />
figerr.com – show <a href="http://en.wikipedia.org/wiki/%D0%94%D1%83%D0%BB%D1%8F" target="_blank">‘dulya’</a> to errors in your application<br />
donterr.com – do not allow errors to sleep into your application<br />
mustdier.com – no comments <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
mustdierr.com &#8211; place where errors die</p>
<p>Looks like we need a break. Will print aboriginal dictionaries today and have a look once again.</p>
<p><strong>Wed Feb 03, 2010 2:02 pm &#8211; Igor</strong></p>
<p>testyfire.com &#8211; what about this one &#8216;fire tests with testyfire&#8217;?</p>
<p>testifire.com is already taken but testyfire is even better as it looks like tasty/test=testy (well I remember dangers of starting with test&#8230; –  ok, ok)</p>
<div style="float: right;"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/naming_chr_1.jpg" alt="" width="208" height="279" /></div>
<p>moonfier.com<br />
bugfrier.com<br />
bugfier.com<br />
vemoon.com &#8211; virtual Selenium cloud<br />
bugmuter.com<br />
antibuz.com<br />
antibuzzer.com<br />
bugjiuce.com<br />
moongun.com<br />
moonoh.com<br />
testoh.com<br />
moonte.com<br />
buginar.com<br />
bugoh.com<br />
shotomo.com &#8211; this one like Japanese sushi bar <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  &#8217;shot&#8217; &#8216;moon&#8217;<br />
debugie.com &#8211; has debug and bugie and also like bungie<br />
moongie.com</p>
<p>arilpa.com &#8211; aboriginal &#8216;moon&#8217;<br />
gigalee.com &#8211; aboriginal &#8216;moon&#8217;</p>
<p>goondooloo.com &#8211; Southern Cross but typing it will be a nightmare. Will anybody need to type it?<br />
goolabah.com &#8211; box tree – just sounds nice</p>
<p>nananga.com &#8211; &#8216;moon&#8217;<br />
woolahra.com &#8211; &#8216;moon&#8217;<br />
tanaranga.com &#8211; &#8216;moon&#8217;</p>
<p><strong>Wed Feb 03, 2010 6:08 pm &#8211; Igor</strong></p>
<p>While you were sleeping Oleg and I exchanged quite a lot of emails and summary of preferences we have:</p>
<p>Debugie<br />
Debuggie<br />
Gigalee<br />
Tanaranga</p>
<p>It does not mean you have to agree or select from these ones.</p>
<p><strong>Wed Feb 03, 2010 9:04 pm &#8211; Alex</strong></p>
<p><span class="forum_quote"> Igor: &#8220;Debugie&#8221;</span></p>
<p>I associate it with debug + IE</p>
<p><strong>Wed Feb 03, 2010 9:33 pm &#8211;  Igor</strong></p>
<p><span class="forum_quote"> Alex: &#8220;I associate it with debug + IE&#8221;</span></p>
<p>Популярный суффикс  &#8211; ничего особенного<br />
Самое извесное название пришедшее в голову http://www.bungie.com(net).</p>
<p>Quite popular suffix <a href="http://www.onelook.com/?w=*ie&amp;scwo=1&amp;sswo=0" target="_blank">-ie</a> nothing microsoft-ish in it.  Most famous will be probably http://www.bungie.com(net).</p>
<p><strong>Wed Feb 03, 2010 10:52 pm &#8211; Igor</strong></p>
<p>Travelling north from Sydney along the coast by map:<br />
mallabulla.com<br />
bootibooti.com<br />
mooneba.com<br />
kremnos.com<br />
deebung.com – minor variation from real &#8216;geebung&#8217;<br />
deebuh.com – imaginary but looked at the names on a map<br />
deeplie.com – imaginary but looked at the names on a map<br />
neerdie.com – real one</p>
<p><strong>Wed Feb 03, 2010 11:31 pm &#8211; Alex</strong></p>
<p><span class="forum_quote"> Igor: &#8220;deebuh.com&#8221;</span></p>
<p>It&#8217;s funny.  We can consider it as deep + BUH! The bigger they are the harder they fall.</p>
<p><span class="forum_quote"> Igor: &#8220;deeplie.com&#8221;</span></p>
<p>Very easy and resounding, I like it. Somehow, I immediately wanted to check domain figli.com. It is registered until 11th Feb 2010. We may be lucky and it will expire and become available.</p>
<p><strong>Thu Feb 04, 2010 12:55 am &#8211; Dmitriy</strong></p>
<p><span class="forum_quote"> Igor:<br />
&#8220;deebung.com<br />
deebuh.com<br />
deeplie.com<br />
neerdie.com&#8221;</span></p>
<p>It&#8217;s pretty nice &#8211; but how to choose one?<br />
I feel we will finally write names down on pieces of paper and pull out of it.</p>
<p><strong>Wed Feb 03, 2010 13:25 pm &#8211; Oleg</strong></p>
<p>The word &#8216;lie&#8217; has implications. Deeplie sounds more like a conspiracy theory website <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Thu Feb 04, 2010 8:55 pm &#8211; Dmitriy</strong></p>
<p><span class="forum_quote"> Igor:<br />
&#8220;deeplie.com<br />
figlee.com&#8221;</span></p>
<p>I also like both. We could use &#8216;deeplee&#8217; to disassociate &#8216;deeplie&#8217; from a lie, but it is taken.</p>
<p><strong>Thu Feb 04, 2010 9:06 pm &#8211; Alex</strong></p>
<p><span class="forum_quote"> Igor:<br />
&#8220;deeplie.com<br />
figlee.com&#8221;</span></p>
<p>Yes, both names are good, hard to choose.</p>
<p><strong>Fri Feb 05, 2010 9:42 pm &#8211; Alex</strong></p>
<p><span class="forum_quote"> Igor: &#8220;Google calls things this way – <a href="http://code.google.com/apis/pubsubhubbub/" target="_blank">PubSubHubbub</a>&#8220;</span></p>
<p>Things allowed the gods, are not available for the mortals <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Tue Feb 09, 2010 10:19 pm &#8211; Igor</strong></p>
<p><span class="forum_quote"> Alex: &#8220;So, let’s use Deeplie.com? We have already started using it in our forum <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> &#8221;</span></p>
<p>I do not know about you, but I will just do other things and look at all the names again after the break.</p>
<p><strong>Mon Feb 15, 2010 2:48 pm &#8211; Igor</strong></p>
<p><span class="forum_notes">(10 days past &#8211; author&#8217;s note)</span></p>
<p>Appear to be available:</p>
<p>prompty.com – from dictionary &#8220;prompt – ready in action; quick to act as occasion demands.&#8221;</p>
<p>аs well as:<br />
promptie.com<br />
promtie.com</p>
<p><strong>Mon Feb 15, 2010 4:48 pm &#8211; Oleg</strong></p>
<p>deeplie &#8211; can be associated with &#8216;deep lie&#8217;<br />
feeglee &#8211; can be associated with &#8216;fig leaf&#8217;</p>
<p>Both are not very good.</p>
<p>prompty.com is neutral</p>
<p>I looked through old names. Do you like gigalee.com &#8211; it is aboriginal and it is moon(selen) &#8211; so nobody can say we tried to get as many &#8216;g&#8217; as google has  <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Mon Feb 15, 2010 9:35 pm &#8211; Alex</strong></p>
<p><span class="forum_quote"> Oleg: &#8220;prompty.com is neutral&#8221;</span></p>
<p>Sounds a bit &#8216;mumbly&#8217;</p>
<p><span class="forum_quote"> Igor: &#8220;velenium.com or vellenium.com – as Virtual sELENIUM&#8221;</span></p>
<p>Velenium sounds nice.</p>
<p><span class="forum_quote"> Igor: &#8220;virshify.com – using virtlib command ‘virsh’ used to manipulate virtual machines.&#8221;</span></p>
<p>All consonant sounds are muffled and sizzling. And we still remember name nerrvana.com <span class="forum_notes">(this was Alex who turned us back to it &#8211; author&#8217;s note)</span> and we still like it.</p>
<div style="float: right;"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/naming_chr_5.jpg" alt="" width="408" height="244" /></div>
<p><strong>Mon Feb 15, 2010 10:21 pm &#8211; Igor</strong></p>
<p>I remember nirvanium.com<br />
nerrvana? Which post?</p>
<p><strong>Tue Feb 16, 2010 9:39 am &#8211; Igor</strong></p>
<p>Morning recap:<br />
nerrvana<br />
nirvanium<br />
velenium</p>
<p><strong>Tue Feb 16, 2010 8:10 pm &#8211; Igor</strong></p>
<p>Morning workouts with &#8216;err&#8217;</p>
<p>eterrnity.com</p>
<p>Is &#8216;eterrnity&#8217; a bad association? I do not know how to think of eternity as &#8216;timeless&#8217; as I do not want it to be associated with never ending process</p>
<p>Motto could be: in eternal (never ending) search of errors (not never ending system work)</p>
<p>counterr.com<br />
enderr.com<br />
eraserr.com<br />
executerr.com<br />
explorerr.com<br />
vierr.com &#8211; makes errors visible<br />
shifterr.com &#8211; Shift Labs approach for searching errors</p>
<p>fryerr.com &#8211; deep frying bugs since 2010<br />
runerr.com<br />
rulerr.com &#8211; a new way to debug errors with Selenium</p>
<p>Anything touched?</p>
<p><strong>Tue Feb 16, 2010 9:00 pm &#8211; Dmitriy</strong></p>
<p><span class="forum_quote"> Igor: &#8220;Anything touched?&#8221;</span></p>
<p>Yep, use of ‘err’ in the end &#8211; perfect!</p>
<p>I like:<br />
enderr.com<br />
eraserr.com<br />
shifterr.com</p>
<p>First two are similar to killerr (btw domain is available!).</p>
<p>shifterr – good.<br />
Shifter is also &#8220;an adjustable wrench/spanner&#8221; but it is ok.</p>
<p><strong>Wed Feb 17, 2010 4:40 pm  &#8211; Igor</strong></p>
<div style="float: right;"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/naming_chr_2.jpg" alt="" width="238" height="141" /></div>
<p>Err at the beginning:<br />
erraser.com<br />
erraserr.com</p>
<p>Unfortunately zerro.com is taken.</p>
<p><strong>Wed Feb 17, 2010 10:40 pm &#8211; Alex</strong></p>
<p><span class="forum_quote"> Igor: &#8220;Anything touched?&#8221;</span></p>
<p>Not bad – enderr.com</p>
<p><strong>Thu Feb 18, 2010 9:31 am &#8211; Igor</strong></p>
<p><span class="forum_quote"> Alex: &#8220;Not bad – enderr.com&#8221;</span></p>
<p>Your and Oleg’s point of views matched this time, and he likes our names very rarely.<br />
New names are born every day now. It has probably became a habit.</p>
<p><a href="http://en.wikipedia.org/wiki/%C3%89clair_%28pastry%29" target="_blank">eclerr</a>.com<br />
testerr.com<br />
enderr – easy to say and a good combination of words ‘end errors’</p>
<p><strong>Thu Apr 08, 2010 11:14 pm &#8211; Alex</strong></p>
<p><span class="forum_quote"> Igor: &#8220;eclerr.com&#8221;</span></p>
<p>Éclair &#8211; not our audience. Beer-air, chips-air fit perfectly  <img src='http://www.deepshiftlabs.com/dev_blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><span class="forum_quote"> Igor: &#8220;enderr.com – good name but hard on pronunciation a bit (compare with velenium)&#8221;</span></p>
<p>Completely agree especially for people who speak with a lisp.</p>
<p><span class="forum_quote"> Igor: &#8220;nerrvana.com – I would like to check trademark&#8221;</span></p>
<p>Hmm, interesting name.</p>
<p><span class="forum_quote"> Igor: &#8220;velenium.com – easy to pronounce and associated with Virtual Selenium&#8221;</span></p>
<p>Also not bad.</p>
<p><span class="forum_quote"> Dmitriy: &#8220;We also had: deepium.com, deelium.com, deesbug.com, bugspell.com&#8221;</span></p>
<p>Comparing with nerrvana.com and velenium.com they definitely loose.</p>
<p>This concludes our naming chronicles and discussion switched to the logo, and this, as they say, is another story. Somehow without even voting, we have registered nerrvana.com and started using a new name &#8211; <strong>Nerrvana</strong>.</p>
<p><img class="aligncenter" style="-ms-interpolation-mode: bicubic;"  src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/05/nerrvana.png" alt="" width="419" height="170" /></p>
<hr /><sup>*</sup> &#8211; USA trademarks can be checked on <a href="http://tess2.uspto.gov/" target="_blank">USPTO</a> site<br />
<sup>**</sup> &#8211; Parascale was <a href="http://www.theregister.co.uk/2010/08/20/hds_parascale/" target="_blank">acquired</a> by Hitachi Data Systems<br />
</p>
<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/eWNRIl8RQf0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=935&amp;lang=en-us</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=935&amp;lang=en-us</feedburner:origLink></item>
		<item>
		<title>Assign dynamic IP to VM without DHCP</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/PB7xzksaYKY/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=933&amp;lang=en-us#comments</comments>
		<pubDate>Sat, 30 Apr 2011 13:52:47 +0000</pubDate>
		<dc:creator>bear</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=933</guid>
		<description><![CDATA[The system we are developing is intensively using virtual machines. When the system core requires another machine it copies the template image, and starts it. Thus, many copies of essentially the same machine can work simultaneously.
Of course, at launch each virtual machine is identical to the template including the inherited set of the network settings. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.thinkgeek.com/tshirts-apparel/unisex/generic/5d6a/"><img class="alignleft size-full wp-image-1179" title="noplace" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/noplace_smaller.jpg" alt="" width="160" height="205" /></a>The system we are developing is intensively using virtual machines. When the system core requires another machine it copies the template image, and starts it. Thus, many copies of essentially the same machine can work simultaneously.</p>
<p>Of course, at launch each virtual machine is identical to the template including the inherited set of the network settings. All virtual machines run on the same subnet, and therefore they should not use the same IP obtained from the template image to prevent conflicts. That is, each machine should get its own IP. It would seem that the solution is simple &#8211; use a DHCP server and dynamic IPs.</p>
<p>However, there are other options which I will discuss in this post.<br />
<span id="more-933"></span><br />
<a href="#why">1. Why do we need virtual machines?</a><br />
<a href="#problem">2. The problem of duplicate IP addresses when running multiple VM clones</a><br />
<a href="#ip_encoding">3. Encoding IP into MAC address</a><br />
<a href="#get_ip_dhcp">4. Allocating IP by MAC: DHCP</a><br />
<a href="#get_ip_script">5. Allocating IP by MAC: mac2ip script</a><br />
<span style="margin: 15px;"><a href="#linux">a) Linux</a></span><br />
<span style="margin: 15px;"><a href="#windows">b) Windows</a></span><br />
<a href="#notes">6. Final notes</a><br />
<a name="why"></a></p>
<h3>1. Why do we need virtual machines?</h3>
<p style="text-align: left;">Our project, Nerrvana, executes functional tests for web applications in different browsers. Tests are run with a special framework for functional testing &#8211; Selenium, which can simulate user actions inside a browser (clicks on elements, mouse movements, data input, text reading), make screenshots of web pages and some other stuff.</p>
<p>A web application test is a sequence of actions emulating user behavior, and comparison of their outcomes with expected ones. For example, a simple test &#8211; a login. You need to open the login page, enter your login and password, press enter, and make sure we&#8217;re logged in &#8211; say, seeing the standard welcome message which includes username. Everyone knows that browsers can quite differently display and work with the same page, and so it makes sense to perform the same tests in the most popular browsers. As I already mentioned, our system does just that &#8211; it launches Selenium grid in a virtual environment and executes tests.</p>
<p>Tests in the selected browsers and operation systems are run simultaneously and completely independently from each other. Execution of a test suite in one environment was given a funny name by us &#8211; speck. If I want, for example, to test login functionality inside IE8 and FF3.6, our system will create two independent specks and will launch tests using selected browsers. Not going into details too much, I should say that for every speck we create at least two virtual machines. One is a &#8220;hub&#8221;, will execute tests. It can launch tests in Java or PHP we support for now. The second machine is a &#8220;tester&#8221;, running Selenium RC, OS and the browser of your choice. Selenium RC is an interaction point between tests executed on the &#8220;hub&#8221; and a browser.<br />
<a name="problem"></a></p>
<h3>2. The problem of duplicate IP addresses when running multiple VM clones</h3>
<p>We have a template image for each type of a virtual machine. When the core of the system requires another machine, this image is copied, and runs. The template image itself remains unchanged. Thus, many copies of essentially the same machine can be up and running at the same time.</p>
<p>And here a problem arises.<br />
Naturally, at the moment of launch each virtual machine is identical to the template. All settings are inside an image, which can not be altered. This obviously includes a network setup. Since all the virtual machines run on the same subnet, it is clear that they must not use same IP, obtained from a template machine to prevent conflicts. So, each machine must dynamically obtain its own IP. It would seem that the solution is simple &#8211; to use a DHCP server, which will give each machine a unique address.</p>
<p>However, not all that easy. The fact is our core actively interacts with virtual machines. It plays an active role keeping virtual machines as slaves and doing a lot of work with them: makes sure all virtual machines (VMs) in a grid have successfully started, starts Selenium RC on all testers, loads and executes code on the hub, monitors tests execution, and then gets back results (screenshots, logs, etc.) before destroying VMs. System core, anyway, need to know VMs IP addresses which were just launched on its&#8217; request.</p>
<p>We had two solutions in mind:<br />
1) Once the virtual machine is booted, it gets a random address from DHCP, and then somehow registers itself with the core by saying: &#8220;I am &#8211; a machine of a this type. My IP, received from the DHCP, is this&#8221;.<br />
2) Somehow, the core tells VM what address it should use. Here the core knows VMs&#8217; IP before it boots.</p>
<p>The first approach seemed to us quite difficult to implement for several reasons. It required some shift of responsibilities from the core to VMs (we wanted to keep them as slaves), problems with matching requested and registered VMs as well as some inconveniences in changing core components.<br />
The second option was more appealing to us, because the core has full control over the VM from the point of its creation without an uncertainty period while waiting for the VM to boot and register itself from option one.<br />
<a name="ip_encoding"></a></p>
<h3>3. Encoding IP into MAC address</h3>
<p>How could we pass an IP to a starting VM? We have found the following way: when you start a virtual machine, you can specify a MAC address of the virtual network adapter. A virtual machine itself can read it any time. Our &#8216;invention&#8217; was to use MAC address as a carrier of information about the IP (could be anything you want).</p>
<p>How we encode IP into MAC address? We use <a title="xen" href="http://en.wikipedia.org/wiki/Xen" target="_self">Xen</a> for virtualization, and its virtual NICs must have MACs assigned which look like this: 00:16:3E:XX:XX:XX, where 00:16:3E &#8211; network adapter manufacturers&#8217; code. We can use last three bytes at our discretion (remembering, of course, the fact that the MAC must be unique). Suppose that our system will be set on the subnet 10.0.0.0/8. A logical decision in this case will be to use for the last three bytes of MAC corresponding to the last three bytes of IP addresses that we want to encode. For example, to start VM with IP 10.1.1.3, we start VM with MAC 00:16:3E:01:01:03.</p>
<p>Now we only need to teach the VM to get an IP from its MAC. Again, this can be done in two ways.<br />
<a name="get_ip_dhcp"></a></p>
<h3>4. Allocating IP by MAC: DHCP</h3>
<p>The first way is pretty obvious. We will run a DHCP server, which will be configured to give IP by MAC-address in accordance with the described above method. Template image must be configured with DHCP enabled.</p>
<p>Work scenario will look like this:<br />
1) The core needs to start a VM.<br />
2) The core looks at IP-addresses pool, chooses the first unoccupied IP (for example, 10.4.0.15), and converts it to a MAC (00:16:3E:04:00:0F)<br />
4) The core makes the template image copy and prepares a VM configuration file (which contains MAC address)<br />
5) The core launches the prepared VM<br />
6) OS inside launched VM requests IP address from DHCP server. DHCP server checks its MAC to IP table and responds with IP 10.4.0.15.<br />
7) The core is pinging 10.4.0.15, and upon receiving a response, continues to work with a virtual machine (in our case connecting via ssh)</p>
<p>Pluses and minuses:<br />
<strong>-</strong> requires a DHCP server<br />
<strong>-</strong> if we move to a different subnet or get a different pool of IP-addresses, we will have to reconfigure not only the core but also a DHCP server<br />
<strong>+</strong> uses a standard approach to dynamic IP allocation</p>
<p><a name="get_ip_script"></a></p>
<h3>5. Allocating IP by MAC: mac2ip script</h3>
<p>The second approach is less obvious and requires some extra work. It lies in a need to create an extra script which will be injected into OS start-up process. It will get a MAC address, convert it to an IP, and assign it to a network card. Work scenario will be the same with the exception of point 6 which will read:</p>
<p>6) OS&#8217;s start up script inside launched VM will read MAC, convert it to an IP address and assign it to VM&#8217;s network interface.</p>
<p>Pluses and minuses:<br />
<strong>+</strong> no need for DHCP server and MAC to IP conversion table maintenance inside it<br />
<strong>-</strong> each type of OS will require own implementation of mac2ip script</p>
<p>We implemented the mac2ip approach. We are working with virtual machines running CentOS 5.6 and Windows XP PRO SP3, and so we had two scripts mac2ip &#8211; for each of the systems.<br />
Let&#8217;s look at both scripts.<br />
<a name="linux"></a></p>
<h5>a) Linux</h5>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p933code24'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p93324"><td class="code" id="p933code24"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/bash</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># first byte will always be equal to 10</span>
<span style="color: #007800;">IP1</span>=<span style="color: #000000;">10</span>
&nbsp;
<span style="color: #007800;">IFCFG</span>=<span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>sysconfig<span style="color: #000000; font-weight: bold;">/</span>network-scripts<span style="color: #000000; font-weight: bold;">/</span>ifcfg-eth0
<span style="color: #007800;">NETWORK</span>=<span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>sysconfig<span style="color: #000000; font-weight: bold;">/</span>network
&nbsp;
<span style="color: #000000; font-weight: bold;">case</span> <span style="color: #ff0000;">&quot;$1&quot;</span> <span style="color: #000000; font-weight: bold;">in</span>
<span style="color: #000000; font-weight: bold;">*</span>start<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000; font-weight: bold;">;;</span>
<span style="color: #000000; font-weight: bold;">*</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">exit</span>
<span style="color: #000000; font-weight: bold;">;;</span>
<span style="color: #000000; font-weight: bold;">esac</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># get MAC and validate it</span>
<span style="color: #007800;">MAC</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">ifconfig</span> eth0<span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">grep</span> HWaddr<span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">awk</span> <span style="color: #ff0000;">'{print $NF}'</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">grep</span> ^00:<span style="color: #000000;">16</span>:3E<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-z</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$MAC</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> ; <span style="color: #000000; font-weight: bold;">then</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Can't determine MAC address&quot;</span> <span style="color: #000000; font-weight: bold;">&amp;</span>gt;<span style="color: #000000; font-weight: bold;">&amp;</span>amp;<span style="color: #000000;">2</span>
<span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">1</span>
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># convert MAC to IP</span>
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #660033;">--</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #007800;">$MAC</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">awk</span> -F: <span style="color: #ff0000;">'{print $4,$5,$6}'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #007800;">IPADDR</span>=<span style="color: #800000;">${IP1}</span>.$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>0x$<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>.$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>0x$<span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>.$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>0x$<span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># change network inreface</span>
<span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #660033;">-i</span> <span style="color: #660033;">-e</span> <span style="color: #ff0000;">&quot;s/^IPADDR.*/IPADDR=<span style="color: #007800;">$IPADDR</span>/&quot;</span> <span style="color: #007800;">$IFCFG</span>
<span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #660033;">-i</span> <span style="color: #660033;">-e</span> <span style="color: #ff0000;">&quot;/^HWADDR/d&quot;</span> <span style="color: #007800;">$IFCFG</span>
<span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #660033;">-i</span> <span style="color: #660033;">-e</span> <span style="color: #ff0000;">&quot;s/^HOSTNAME.*/HOSTNAME=localhost/&quot;</span> <span style="color: #007800;">$NETWORK</span></pre></td></tr></table></div>

<p>Now force this script to run before the network starts.<br />
<a name="windows"></a></p>
<h5>b) Windows</h5>
<p>As you expect the same work on Windows XP is done in more arcane ways. Perhaps, over time, we will find a better way to convert MAC to IP.</p>
<p>The first problem I encountered is that it is relatively hard to change the interface BEFORE it will be enabled. Thus, the template VM must have default networking turned off by default as otherwise two or more simultaneously launched VMs running Windows will conflict with their identical IPs (it is static, because we are not using DHCP).</p>
<p>Ok, this is not the problem &#8211; we can turn off network interface. However, the utility <a href="http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/getmac.mspx?mfr=true"> getmac</a>, which we will be using to get MAC address can not return it for the turned off interface! To work around it we will assign a random interface IP first, turn interface on, get MAC, and finally assign a correct IP.</p>
<p>We used <a title="devcon" href="http://support.microsoft.com/kb/311272/en-us" target="_self">devcon</a> utility to manipulate devices.<br />
Here&#8217;s how it looks:</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p933code25'); return false;">View Code</a> WINBATCH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p93325"><td class="code" id="p933code25"><pre class="winbatch" style="font-family:monospace;"><span style="color: #66cc66;">@</span>echo <span style="color: #0080FF; font-weight: bold;">off</span>
SET MAC=
SET IP=
SET MASK=255.255.255.0
SET GATEWAY=
&nbsp;
rem get <span style="color: #0000FF;">random</span> IP. This IP will be used <span style="color: #800080;">for</span> a few seconds,
rem and this is why it is good enough <span style="color: #800080;">to</span> <span style="color: #0000FF;">random</span> generate two last bytes.
rem <span style="color: #cc66cc;">100</span> <span style="color: #66cc66;">-</span> <span style="color: #0080FF; font-weight: bold;">shift</span>, <span style="color: #800080;">to</span> assure that we will not use any used IP.
set <span style="color: #66cc66;">/</span>A TEMP_THIRD_BYTE=<span style="color: #cc66cc;">100</span><span style="color: #66cc66;">+%</span><span style="color: #0000FF;">RANDOM</span><span style="color: #FF1010; font-weight: bold;">:~0,2%</span>
set <span style="color: #66cc66;">/</span>A TEMP_FOURTH_BYTE=<span style="color: #cc66cc;">100</span><span style="color: #66cc66;">+%</span><span style="color: #0000FF;">RANDOM</span><span style="color: #FF1010; font-weight: bold;">:~0,2%</span>
set TEMP_IP=<span style="color: #ff0000;">&quot;192.168.%TEMP_THIRD_BYTE%.%TEMP_FOURTH_BYTE%&quot;</span>
set TEMP_GATEWAY=<span style="color: #ff0000;">&quot;192.168.%TEMP_THIRD_BYTE%.1&quot;</span>
&nbsp;
rem set network interface params
netsh interface ip set address local static <span style="color: #66cc66;">%</span>TEMP_IP<span style="color: #66cc66;">%</span> <span style="color: #66cc66;">%</span>MASK<span style="color: #66cc66;">%</span> <span style="color: #66cc66;">%</span>TEMP_GATEWAY<span style="color: #66cc66;">%</span> <span style="color: #cc66cc;">1</span>
&nbsp;
rem turn <span style="color: #0080FF; font-weight: bold;">on</span> interface. We use this <span style="color: #800080;">to</span> do it <span style="color: #66cc66;">-</span>
C<span style="color: #FF1010; font-weight: bold;">:\devcon\i386\devcon enable *VEN_10E*</span>
&nbsp;
rem get three last bytes from MAC
<span style="color: #800080;">FOR</span> <span style="color: #66cc66;">/</span>F <span style="color: #ff0000;">&quot;Tokens=4-6 Delims=- &quot;</span> <span style="color: #66cc66;">%%</span>d <span style="color: #800080;">in</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'getmac^|find &quot;Device\Tcpip_&quot;'</span><span style="color: #66cc66;">&#41;</span> do <span style="color: #66cc66;">&#40;</span>
set <span style="color: #66cc66;">/</span>a dec_d=0x<span style="color: #66cc66;">%%</span>d
set <span style="color: #66cc66;">/</span>a dec_e=0x<span style="color: #66cc66;">%%</span>e
set <span style="color: #66cc66;">/</span>a dec_f=0x<span style="color: #66cc66;">%%</span>f
<span style="color: #66cc66;">&#41;</span>
&nbsp;
rem set real IP and gateway
SET IP=10.<span style="color: #66cc66;">%</span>dec_d<span style="color: #66cc66;">%</span>.<span style="color: #66cc66;">%</span>dec_e<span style="color: #66cc66;">%</span>.<span style="color: #66cc66;">%</span>dec_f<span style="color: #66cc66;">%</span>
SET GATEWAY=10.<span style="color: #66cc66;">%</span>dec_d<span style="color: #66cc66;">%</span>.0.1
&nbsp;
rem change interface params <span style="color: #800080;">to</span> real ones
netsh interface ip set address local static <span style="color: #66cc66;">%</span>IP<span style="color: #66cc66;">%</span> <span style="color: #66cc66;">%</span>MASK<span style="color: #66cc66;">%</span> <span style="color: #66cc66;">%</span>GATEWAY<span style="color: #66cc66;">%</span> <span style="color: #cc66cc;">1</span>
netsh interface ip set dns local static <span style="color: #66cc66;">%</span>GATEWAY<span style="color: #66cc66;">%</span></pre></td></tr></table></div>

<p>Add this script into start-up sequence &#8211; for example, this way:</p>

<div class="wp_codebox_msgheader"><span class="right"><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p933code26'); return false;">View Code</a> WINBATCH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table width="100%" ><tr id="p93326"><td class="code" id="p933code26"><pre class="winbatch" style="font-family:monospace;">reg ADD <span style="color: #ff0000;">&quot;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run&quot;</span> <span style="color: #66cc66;">/</span>v <span style="color: #ff0000;">&quot;mac2ip&quot;</span> <span style="color: #66cc66;">/</span>t REG_SZ <span style="color: #66cc66;">/</span>d <span style="color: #ff0000;">&quot;c:\init\mac2ip.bat&quot;</span></pre></td></tr></table></div>

<p>After these scripts completion a VM will receive an IP address specified by the core and will be ready to work. The core will know about it from ping replies from an assigned IP.<br />
Perhaps, this diagram will add some clarity (click for a full-size picture in a new window):</p>
<p style="text-align: center;"><a href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/mac2ip.png" target="_blank"><img class="size-medium wp-image-1181 aligncenter" title="mac2ip_ru" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/mac2ip_300_283_eng.png" alt="" width="300" height="283" /></a></p>
<p><a name="notes"></a></p>
<h3>6. Final notes</h3>
<p>Our approach with mac2ip script is rather slow on Win XP. The current implementation does the job in 15-20 seconds. You understand our feelings if we will say that same 15-20 seconds required from starting OS to a moment mac2ip starts. Script doubles time to launch a VM.</p>
<p>However, we aren&#8217;t in a rush to start using DHCP method (DHCP with binding IP to MAC), because:</p>
<p>- firstly, we know for sure that Linux will boot via DHCP slower than working version with a static address. Will the Windows boot faster with DHCP comparing with mac2ip script? Hard to say. We need to check it out.</p>
<p>- secondly, VMs are not shut down properly in our system. We do &#8216;virsh destroy&#8217; for the VM which is similar to disconnecting power for a physical host. This saves us tons of time as we loaded all the data we needed from VMs and do not care about their integrity. We do not reuse VMs and they will be immediately deleted after use. So, DHCP leased VM address will not be released immediately. It will happen after default-lease-time according to DHCP etiquette. This means that we can not immediately start the VM with the same MAC (and same IP). Setting default-lease-time to a small value (seconds) is not a good idea. A more realistic option &#8211; to look at and use OMAPI/omshell to manipulate DHCP and remove unwanted entries straight after  &#8216;virsh destroy&#8217;ing a VM.</p>
<p>- in third &#8211; any new approach will bring its own hidden pitfalls.</p>
<p>So the slow work of the Windows script in the current version is not a good enough reason to switch to DHCP.</p>
<p style="text-align: right;"><em>What&#8217;s in my name? It&#8217;s soulless,<br />
It shall expire, like the dismal roar<br />
Of waves that hit the distant shore, &#8211;<br />
Like nighttime noises in the forest!</em></p>
<p style="text-align: right;"><em><a href="http://www.kulichki.com/moshkow/LITRA/PUSHKIN/ENGLISH/kneller01.txt">Alexander Pushkin</a></em></p>
<p style="text-align: right;"><em> </em></p>

<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/PB7xzksaYKY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=933&amp;lang=en-us</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=933&amp;lang=en-us</feedburner:origLink></item>
		<item>
		<title>How do we use dotProject</title>
		<link>http://feedproxy.google.com/~r/DeepShiftLabsDevelopmentBlog/~3/wR53q5TCdsA/</link>
		<comments>http://www.deepshiftlabs.com/dev_blog/?p=927&amp;lang=en-us#comments</comments>
		<pubDate>Thu, 28 Apr 2011 14:02:10 +0000</pubDate>
		<dc:creator>Igor Kryltsov</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.deepshiftlabs.com/dev_blog/?p=927</guid>
		<description><![CDATA[

In this post we&#8217;ll talk about dotProject &#8211; a web-based open source project management system. We have used it from 2004 to the present day (seven years). You may consider this post as a mini-guide on the use of dotProject, based on the experience of a team of four developers who build web applications for [...]]]></description>
			<content:encoded><![CDATA[<div style="float: left;"><a href="http://www.dotproject.net/" target="_blank"><img class="alignleft size-full" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/dotProject_tn.png" alt="How do we use dotProject" width="264" height="164" /></a></div>
<p><br />
In this post we&#8217;ll talk about <a href="http://en.wikipedia.org/wiki/DotProject" target="_blank">dotProject</a> &#8211; a web-based open source project management system. We have used it from 2004 to the present day (seven years). You may consider this post as a mini-guide on the use of dotProject, based on the experience of a team of four developers who build web applications for businesses. This post is quite lengthy as we wanted to share our experiences and avoid creating just another impractical review.</p>
<p>It is hard to remember now, amongst which systems I had to choose. I remember that I found dotProject and <a href="http://en.wikipedia.org/wiki/EGroupWare" target="_blank">eGroupWare</a>. Today, according to Wikipedia, there are <a href="http://en.wikipedia.org/wiki/Comparison_of_project_management_software" target="_blank&quot;">tons</a> of such systems. In 2005 the choice was much smaller and the level of their maturity much lower. I have installed dotProject and eGroupWare, and I liked the dotProject &#8211; it had all the features that were needed, and even more. If you&#8217;ve read some of my previous posts, you know that I am not a supporter of services when you have to pay regardless of whether or not you are using the service, where the data can not be easily migrated to another provider. In general, I like <a href="http://en.wikipedia.org/wiki/Vendor_lock-in" target="_blank">lock-in</a> free services and respect people who create them. It is not easy. I want to be able to leave without loosing data or having a headache because of data conversion. In this case we are talking about the data stored in the database and the files that are attached to projects, tasks, etc. Otherwise, I feel insecure and dependent on the service provider. If we talk about project management systems, then this freedom is only given to you by an open source system installed on your server, developed (preferably) on the language you are familiar with. This gives you almost unlimited possibilities &#8211; you can dig up and tweak anything. Rule is simple. If you do not want to tweak &#8211; you can live without it. That&#8217;s why I chose dotProject.<br />
<span id="more-927"></span><br />
Much later I decided to look at the two most frequently mentioned project management systems: <a href="http://basecamphq.com" target="_blank">Basecamp</a> &#8211; with an emphasis in simplicity, and <a href="http://en.wikipedia.org/wiki/FogBugz" target="_blank">FogBugz</a> &#8211; with a bias in bug-tracking, and I must tell you that even if they were free and downloadable (not <a href="http://en.wikipedia.org/wiki/SaaS" target="_blank">SaaS</a>) systems, then I would still chose dotProject. I did not see anything terribly missing for my work in them. FogBugz differentiates itself with <a href="http://en.wikipedia.org/wiki/Evidence-based_Scheduling" target="_blank">evidence-based scheduling</a>. It can not be used in our work &#8211; often project undergo a tangible change during development process, so I do not need to know the probability of a new version release by a certain date. Basecamp &#8211; a good system, with minimal functionality, but there is no forum. Posts (messages) in the project <a href="http://basecamphq.com/demos/messages" target="_blank">can be grouped</a> using categories. Categories looks like a tags. For example, &#8216;design&#8217;. If you click &#8216;design&#8217; you will see all top level posts in this category with their bodies. We find it quite unusual. Conventional forum will show only subjects which are easier to absorb (imagine you have 30 posts in &#8216;design&#8217; category). You can not browse all messages in all projects. You need to switch between projects which we found inconvenient. But this is just us &#8211; both products are very successful which tells us we all have different projects to manage with different views on systems to use.</p>
<p>What would I like to tell about dotProject &#8211; system we use?</p>
<p><a name=forum_en></a>First &#8211; we are using an old version 2.0.4 (current one 2.1.15), and only basic dotProject modules. No add-ons. And later in the post you will see that for us (and perhaps for you), even half of the standard modules as well as half of the form fields attached to projects and tasks are not needed. How are we dealing with it? We had two choices &#8211; modify dotProject or simply do not pay attention to it which we selected. We have done one or two upgrades, and then just fixed the bugs and added a few things we needed. Unfortunately, the dotProject team did not want to use our code, we offered <a href="http://www.dotproject.net/vbulletin/archive/index.php?t-7942.html" target="_blank">more</a> <a href="http://www.dotproject.net/vbulletin/archive/index.php?t-7935.html" target="_blank">than</a> <a href="http://forums.dotproject.net/showthread.php?t=8175" target="_blank">once</a>. The system then met our requirements, and only in 2008 we started using <a href="http://www.phpbb.com/" target="_blank">phpBB</a> for discussions in parallel with dotProject forum and later abandoned dotProjects&#8217; forum completely. Why? On one hand, the increased complexity of projects dragged amount of posts in some forums to a thousand and more. Not an issue for phpBB, but not for dotProjects&#8217; forum. We had to spend time to optimize SQL, since loading a page in busy forums was taking 10-20 seconds. On the other hand, in mid-2008 we began to work on our own product &#8211; <a href="http://www.nerrvana.com" target="_blank">Nerrvana</a> &#8211; in dotProject but we decided to try using phpBB instead of internal dotProjects&#8217; forum. Soon it became clear that it was a great idea. Therefore, we advise you to use dotProject for project tasks, time tracking and specifications, and a forum (of your choice &#8211; phpBB, vBulletin, Vanilla) &#8211; for discussions. Later we needed to create forums and provide access to our client. phpBB allowed us to do it with ease. I would hesitate to show customers dotProjects&#8217; forum. It does not have an advanced editor (rich editor) and the ability to insert images etc. Learn more about the advantages of using a specialised forum platform for project management and collaboration in my next post in this series &#8211; <a href="http://www.deepshiftlabs.com/dev_blog/?p=928&#038;lang=en-us" target="_blank">&#8220;How do we use a forum&#8221;</a>.</p>
<p>Why did we need to provide access to a forum for our client, you may ask. The answer is simple &#8211; work on projects with customers via e-mail box is obsolete. Employees are changing, and in a year or two no one remembers why a decision was made. The one who wants to &#8220;change the world&#8221; often does not know why this world was built that way in a first place. Clients manager does not know why the work on the specification stopped. A forum, in contrast to an email, gives answers to all these questions. I did not like the lack of permanent storage for requirements, questions and answers on the project. I wanted to have a place where a new clients&#8217; employee even in a year or two after application launch could easily jump start and be up to date about decisions that were made a long time ago before making suggestions about changing an existing application. A place I can use to get an old project and re-read all by myself if necessary. When our discussions and communication with the customer is in one place, it is very convenient.</p>
<p>The modules we actually use are Projects, Tasks and Files (fig. 1  num. 1). Other modules &#8211; Calendar, Companies, Forum and Contacts are very easy to hide. We do not use them, but as you see, they are not hidden. If you have many clients, use the module Company as an additional filter to view projects and tasks for each client. Tabs for managing users (User Admin) and system (System Admin) are visible only to a user having administrative rights. If you do not want see them &#8211; create a separate account for an administrator, and exclude them from your profile.</p>
<p><a title="Click to enlarge" href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/projects.png" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Projects" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/projects_720.png" alt="Click to enlarge" /></a></p>
<p style="text-align: center;">Fig. 1 Projects<br />
<em>(click to enlarge)</em></p>
<p>As you can see, we have launched 176 projects since 2004 (fig. 1 num. 2) and completed 158. When a project is completed, we keep it for some time in the status Completed, then we set it Inactive flag which moves a project to Archive tab making it automatically invisible on all other pages, which we&#8217;ll talk about further. It is very convenient to be able to get a project from the archive when additional modifications are required. You remove Inactive flag, create a new task and  immediately get access to the file specifications, links to the forum. Development space-time continuum stays uninterrupted. It is very easy to add a new status/tab in dotProject if you need it. For example, Ongoing status was added by me. I wanted to store some projects separately from the InProgress tab.</p>
<p>Figure 1 shows projects view. Lots of information, but we only use a combination of status (depends on tab you selected) and a project name on this page. Neither the percentage of completion, or columns starting from &#8216;Start&#8217; are not used by us. I highlighted project &#8216;Misc&#8217; (fig. 1 num. 3), which, as you see, was created in 2007 (fig. 1 num. 4) and contains 143 tasks, where 72 are assigned to me (fig. 1 num. 5). Project &#8216;Misc&#8217; is used for everything we would like to improve in our application. Sometimes it requires additional research we have no time to do now. Tasks are taken and completed in this projects when we have spare time doing business components (the ones visible to our client) or a critical mass is reached and completing some tasks will save us a considerable amount of development time. For some reason this view does not show up an amount of uncompleted tasks but total versus yours regardless of their status. In fact we have 22 unfinished tasks in this project &#8211; large number of them also means that we are passionate of things we do too.</p>
<p>How do we decide when to create a project, and when a task? It&#8217;s simple. If we will have subtasks, it is a project. If not &#8211; a task. Each new application in our system is a project (in our system, applications are added to the platform similar to SalesForce).</p>
<p>If we follow a project name link on Figure 1, we will see project details (View Project) page shown below.</p>
<p><a title="Click to enlarge" href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/project_det.png" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Project details" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/project_det_720.png" alt="Click to enlarge" /></a></p>
<p style="text-align: center;">Fig. 2 Project details<br />
<em>(click to enlarge)</em></p>
<p>I must admit it is full of fields we do not use too. I think it is better to have more than you need and I can say it very easy to ignore stuff you do not need. For example, I just do not notice the fields (fig. 2 num. 7) and columns (fig. 2 num. 3). Tab &#8216;Forum&#8217; is visible (fig. 2 num. 1) because a lot of old discussions are in dotProjects&#8217; forum, and therefore we can not hide it entirely. The project, shown on Figure 2, is new (created after we started using phpBB as dotProjects&#8217; forum replacement), so you will see a link on our separate internal forum (fig. 2 num. 1), where we discuss sparklines. You see that a project contains five tasks. Details of each tasks can be looked at by clicking on the links (fig. 2 num. 5). If you worked on a specific task and want to update a task log &#8211; it is easy ​​(fig. 2 num. 2). Completed tasks are easy to hide, using a filter (fig. 2 num. 6). &#8216;Gantt Chart&#8217; tab is a feature we also do not use, but the &#8216;Files&#8217; tab is a smooth transition to the files of the project. You will find specifications, screenshots in there.</p>
<p>If we follow a link marked with an arrow at the top of Figure 3, we will end up on the &#8216;Tasks&#8217; page.</p>
<p><a title="Click to enlarge" href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/tasks.png" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Tasks" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/tasks_720.png" alt="Click to enlarge" /></a></p>
<p style="text-align: center;">Fig. 3 Tasks<br />
<em>(click to enlarge)</em></p>
<p>By definition, dotProject displays all your unfinished tasks on this page. If you have too many of them, you can set a flag called Pinned for some tasks, as I do, and use pinned tasks filter to see only those that are directly in the work. Right here you can add an entry into the task log (fig. 3 num. 2), or go to the task itself using the task name link (fig. 3 num. 3). To show you what information we actually use I again marked the fields that we do not use (fig. 3 num. 1).</p>
<p>Now let&#8217;s look at the task page (View Task). I marked the fields that we do not use (fig. 4 num. 6) following already established tradition. Number 1 is showing a field, which can be used to link task and forums&#8217; topic for discussion. Number 4 &#8211; total hours worked; an important and real thing. Progress &#8211; quite a subjective measure, to me, especially when halfway it turns out that you need three times more functionality and not the one discussed when you started. Even without changes in the task anybody can write 95% and get stuck in some place for three days. So we have all our requirements dynamically changing often, and we do not rely on estimates of completion percentage at all. A new task log can be added in two ways (fig. 4 num. 3). Number 2 shows the Files tab. Place where they really are &#8211; but only those which where attached to this task not to the entire project. File can be attached to a project or to a task in dotProject. Logically the Files tab on project view (fig. 2) will show all files attached to a project as well as all files attached to project tasks. For example, if a task is a bug, files attached to this task will be &#8211; screenshots with instructions on how to reproduce this error. dotProject developers created plenty of fields to store URL (two fields for a project, one for a task). Even each task log can include a URL (fig. 4 num 5). In task logs you can use URLs to link with a forum too. You will agree if you were discussing how to do something, somewhere in the middle of the topic and finally did it, then repeating the same thing in a task log will be boring and time consuming. It is much easier to write short &#8211; &#8220;Implemented &#8211; see the link&#8221;, and include a URL linking the task log update with a specific post in the forum with the details of implementation.</p>
<p><a title="Click to enlarge" href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/tasks_det.png" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Task details" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/tasks_det_720.png" alt="Click to enlarge" /></a></p>
<p style="text-align: center;">Fig. 4 Task details<br />
<em>(click to enlarge)</em></p>
<p>And finally, let&#8217;s look at a project files page.</p>
<p><a title="Click to enlarge" href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/files_tab.png" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" title="Project files" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/files_tab_720.png" alt="Click to enlarge" /></a></p>
<p style="text-align: center;">Fig. 5 Project files<br />
<em>(click to enlarge)</em></p>
<p>We practically do not use the link labeled fig. 5 num. 1, because if you open it in our system, you&#8217;ll see a paginated page showing the first twenty or so files with mark &#8220;693 File (s) (24 Page (s))&#8221;. Yes, it contains a convenient filter to display files by project, but there is a better way &#8211; to open a project and &#8216;Files&#8217; tab on it. This page is shown on Figure 5. dotProject is equipped with a primitive, but quite handy version control system for files. If I need to change a specification I checkout (fig. 5 num. 2) it. dotProject notifies all those involved in a project, that document will change. This is perhaps most important, since it alarms everyone to delete local copies of this document. Version control is typically needed for specifications. When you load a new version into dotProject it does not remove the previous ones. Older versions are available by clicking on a number showing total count of file revisions (shown by arrows on fig. 5).</p>
<p>The project, shown on Figure 5, is a good reason for us to talk about dotProject&#8217;s connection with the forum. Numbers 3 and 4 mark two links. One of them points to our internal forum for this project. Another one points to a forum created to discuss the project with the client.</p>
<p>Why do we have a separate forum for a client? First, to ask the client one question we often need a dozen of posts to discuss it. Why to load clients with the information that might be misunderstood or confusing? Secondly, Vadym is in the U.S.A, I am in Australia, and Dmitriy and Alex are in Ukraine. On the one hand, the lack of direct communication, on the other &#8211; all discussions are recorded. It is a fact that writing takes more time so we all are forced to write to a point only. What more could you want? Third, as you probably guessed, our native language &#8211; Russian, but not our clients. It is easier for us to discuss things in our native language.</p>
<p>Thus, since the beginning of using phpBB, we always create two forums for a project. Each task usually requires a new topic. Topic name could be different from the task name, but should clearly relate to the topic and task. However sometimes a task requires several topics. For example, there is a task &#8211; &#8220;Specification&#8221;, and it is immense. I&#8217;ll call topics as: &#8220;Specification &#8211; add/edit/show audit pages&#8221; or &#8220;Specification &#8211; email notifications &#8211; 3 types&#8221;. Therefore, if you open a forum for this project, you will always clearly see specification topics, without even thinking that a specially selected prefix connects all of these topics with a specific task in a project management system. I have tried to show all of this in the diagram below.</p>
<p><a title="Click to enlarge" href="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/dotProject_phpBB_eng.png" target="_blank"><img class="aligncenter" style="-ms-interpolation-mode: bicubic;" src="http://www.deepshiftlabs.com/dev_blog/wp-content/uploads/2011/04/dotProject_phpBB_720_eng.png" alt="" /></a><br />
<span id="1" style="display: none;"><br />
We can have more than one topic to discuss a spec and we do not even need to link because names of tasks and topics speak for themselves<br />
Forum-category (container for other forums)<br />
For own product you do not need a respective forum as there is no client to discuss<br />
Link between Project and Forum<br />
Link between Task and Topic<br />
Hint<br />
This forum is linked to dotProject project but its topics are not<br />
No structure here. We need to ask – we start a new topic<br />
</span></p>
<p style="text-align: center;"><em>(click to enlarge)</em></p>
<p>Forum-categories in phpBB conveniently divide the internal (only us) and external (customers and us) forums.</p>
<p>Finally, I would like to provide some statistics from our dotProject setup.<br />
Projects<sup>1</sup> &#8211; 176<br />
Tasks<sup>2</sup> &#8211; 997<br />
Task logs<sup>3</sup> &#8211; 4909<br />
Total hours<sup>4</sup> &#8211; 23958<br />
Total posts in forum before switch to phpBB<sup>5</sup> &#8211; 8247<br />
Files<sup>6</sup> &#8211; 828<br />
Files total size<sup>7</sup> &#8211; 135.5 Mb<br />
Db dump<sup>8</sup> &#8211; 16.8M</p>
<hr /><sup>1</sup> &#8211; select count(1) from projects;<br />
<sup>2</sup> &#8211; select count(1) from tasks;<br />
<sup>3</sup> &#8211; select count(1) from task_log;<br />
<sup>4</sup> &#8211; select sum(task_log_hours) from task_log;<br />
<sup>5</sup> &#8211;  select count(1) from forum_messages;<br />
<sup>6</sup> &#8211; select count(1) from files;<br />
<sup>7</sup> &#8211; cd /var/www/aws_dp; du -ks files<br />
<sup>8</sup> &#8211; mysqldump -u xxxx -p xxxx &gt; dotproject_db.dump; du -ks dotproject_db.dump</p>

<img src="http://feeds.feedburner.com/~r/DeepShiftLabsDevelopmentBlog/~4/wR53q5TCdsA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.deepshiftlabs.com/dev_blog/?feed=rss2&amp;p=927&amp;lang=en-us</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.deepshiftlabs.com/dev_blog/?p=927&amp;lang=en-us</feedburner:origLink></item>
	</channel>
</rss>

