<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>Thunder Data Systems Blog, Ruby on Rails Custom Software Programming</title>
	<atom:link href="http://thunderdata.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://thunderdata.com/blog</link>
	<description>TDS - General Business, Programming and Code, Ideas for the Web</description>
	<pubDate>Wed, 01 Dec 2010 18:42:52 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Job Position Available</title>
		<link>http://thunderdata.com/blog/category/job-position-available/</link>
		<comments>http://thunderdata.com/blog/category/job-position-available/#comments</comments>
		<pubDate>Wed, 01 Dec 2010 18:42:52 +0000</pubDate>
		<dc:creator>Stacy</dc:creator>
		
		<category><![CDATA[Random Business Thoughts]]></category>

		<category><![CDATA[Team Dynamics]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=390</guid>
		<description><![CDATA[We just posted a position to our website today for a writing position at Thunder Data.  We are seeking an intern to write articles and blog posts for ThunderTix, a ticketing software to help manage events for small venues to sell tickets. We are looking for a talented writer to create both educational articles and [...]]]></description>
			<content:encoded><![CDATA[<p>We just posted a position to our website today for a writing position at Thunder Data.  We are seeking an intern to write articles and blog posts for <a class="urllink" href="http://www.thundertix.com/" target="_blank">ThunderTix</a>, a ticketing software to help manage events for small venues to sell tickets. We are looking for a talented writer to create both educational articles and short blog posts. We&#8217;ll provide the topics and concepts for each writing assignment.</p>

<p>This is a paid position with flexible hours for a college intern or graduate interested in part-time work.  All work can be performed outside the office, so close proximity to our office is not necessary.  Our preferred candidate would be working towards a degree in either English or Journalism.  Experience in marketing or public relations is a plus, but is not required. </p>

<p>If you are interested in this position or know someone who might be, please send resumes and/or a portfolio to <a href="mailto:careers_info@thunderdata.com">careers_info@thunderdata.com</a>.</p>

<p>Come and join our team!</p>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/job-position-available/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Using PHP&#8217;s preg_match() to Parse Credit Card Data from Magnetic Swipe Readers</title>
		<link>http://thunderdata.com/blog/category/using-phps-preg_match-to-parse-credit-card-data-from-magnetic-swipe-readers/</link>
		<comments>http://thunderdata.com/blog/category/using-phps-preg_match-to-parse-credit-card-data-from-magnetic-swipe-readers/#comments</comments>
		<pubDate>Wed, 13 Oct 2010 17:24:15 +0000</pubDate>
		<dc:creator>Dawn</dc:creator>
		
		<category><![CDATA[TDS Developer's Corner]]></category>

		<category><![CDATA[credit card swipe]]></category>

		<category><![CDATA[magnetic strip reader]]></category>

		<category><![CDATA[magnetic swipe reader]]></category>

		<category><![CDATA[parsing magnetic strip data]]></category>

		<category><![CDATA[php]]></category>

		<category><![CDATA[PHP tutorial]]></category>

		<category><![CDATA[preg_match]]></category>

		<category><![CDATA[regex]]></category>

		<category><![CDATA[regular expressions]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=286</guid>
		<description><![CDATA[Credit card data read from magnetic swipe card readers can be parsed using PHP's preg_match and regular expressions.  Learn how in this tutorial.]]></description>
			<content:encoded><![CDATA[<p>Magnetic swipe card readers via USB can facilitate faster credit card processing.  This is particularly important for our <a href='http://thundertix.com'>ThunderTix</a> clients whose box offices must move patrons past the ticket window as quickly as possible.  This week, a client from one of our legacy PHP apps asked us if we could implement a swipe reader for his own administrative checkout page.  I thought it would be a good time to create a tutorial for parsing the credit card string using PHP and regular expressions.</p>

<p>Our client wanted the ability to enter either all form fields during the checkout process by manual entry or only some of the required fields when swiping the card during a purchase.  We create a form for the checkout:</p>

<p><code ></p>

<form action='' method='POST'  name='pay' />

<pre><code>&lt;span style='required'&gt;*&lt;/span&gt; - Indicates required field.
&lt;div class='fields'&gt;First Name&lt;/div&gt;
  &lt;input type=text name='first_name'&gt;&lt;span style='required'&gt;*&lt;/span&gt;
&lt;/div&gt;
&lt;div class='fields'&gt;Last Name&lt;/div&gt;
  &lt;input type=text name='last_name'&gt;&lt;span style='required'&gt;*&lt;/span&gt;
&lt;/div&gt;
&lt;div class='fields'&gt;Expiration&lt;/div&gt;
  &lt;input type=text size=8 name='expiration'&gt;&lt;span style='required'&gt;*&lt;/span&gt;(MMYY)
&lt;/div&gt;
&lt;div class='fields'&gt;CVV Code&lt;/div&gt;
  &lt;input type=text size=8 name='cvv'&gt;&lt;span style='required'&gt;*&lt;/span&gt;
&lt;/div&gt;
&lt;div class='fields'&gt;Credit Card Number&lt;/div&gt;
  &lt;input type=text name='card'&gt;&lt;span style='required'&gt;*&lt;/span&gt;
&lt;/div&gt;
</code></pre>

<p></code></p>

<p>Now, how do we bypass the validation for the required fields?  Using regular expressions, we can both assess whether the credit card post variable is from the magnetic stripe data and parse the string itself when a match exists.</p>

<p>The string generated from a magnetic stripe reader looks like this :</p>

<pre>
    <span style='color:red;font-weight:bold'>%B</span>4444490633714269<span style='color:red;font-weight:bold''>^</span>DOE<span style='color:red;font-weight:bold''>/</span>JANE B<span style='color:red;font-weight:bold''>^</span>12101010000000379000000<span style='color:red;font-weight:bold''>?    </span>
</pre>

<p>The data from the string is divided by the start sentinel (%B), the end sentinel (?), and field separators (^ and /).  So, we need to create a regular expression to  parse the pieces out.  We&#8217;ll create the following regex pattern and save it to the <code>$swipe</code> variable.</p>

<pre>$swipe = "/^(%B)([0-9]{16})(^)([a-zA-Z-s]*)(/)([a-zA-Z-s]*)(^)([0-9]{2})([0-9]{2})(.)*?$/";</pre>

<p>Let&#8217;s break down our regular expression:</p>

<pre>
  <span><strong>/^(%B)</strong>  = Start Sentinel and format Code (alpha only)</span><br />
  <span><strong>([0-9]{16})</strong> = Primary account number is 16 digits long, accepts only numeric characters</span><br />
  <span><strong>(^) </strong> = Field Separator</span><br />
  <span><strong>([a-zA-Z-]*)</strong>  =  Last Name contains only alpha characters, a space, or a dash.  Note the <code>-</code> and <code>s</code>are escaped</span><br />
  <span><strong>(/) </strong>= Separator between first and last name (escaped forward slash)</span> <br />
  <span><strong>([a-zA-Z-]*) </strong>=  First Name accepts only alpha, spaces, or dashes </span><br />                    
  <span><strong>(^)</strong> = Field Separator</span><br />
  <span><strong>([0-9]{2})</strong> = Expiration year is two digits, accepts only numeric characters</span><br />
  <span><strong>([0-9]{2})</strong>  = Expiration month is two digits, accepts only numeric characters</span><br />
  <span><strong>(.)*?$/</strong>  = The "(.)*" sequence is any other characters that follow through to the end sentinel for the mag data represented by a  the Question Mark is reMagnetic Data 'end sentinenel'</span><br />
</pre>

<p>So, now we&#8217;ll move onto the form&#8217;s action.  We&#8217;ll use <code>preg_match</code> to compare our <code>$_POST['card']</code> string to our regex contained in <code>$swipe</code>.  The result is held in the <code>$matches</code> array.  If a match exists, it is held in <code>$matches[0]</code>, and <code>$matches[1]</code> contains the first parenthesized value, <code>$matches[2]</code> contains the next (of actual card number), and so on.  We&#8217;ll assign these to the $_POST variables, so our form can be processed as if the data had been entered into the fields individually.  If there is no match, standard validation processing occurs.</p>

<pre>
if($_POST['action'] == 'pay') {
  $swipe = "/^(%B)([0-9]{16})(^)([a-zA-Z-s]*)(/)([a-zA-Z-s]*)(^)([0-9]{2})([0-9]{2})(.)*?$/";
  
  if (preg_match($swipe, $_POST['x_card_num'], $matches)) {
    $_POST['card'] =  $matches[2];
    $_POST['first_name'] = $matches[6];
    $_POST['last_name'] =  $matches[4];
    $_POST['expiration'] = $matches[9]."".$matches[8];
  }  else {
    perform_validation_procedures ...
}
</pre>

<p>A couple of final notes: if using Authorize.net as your gateway, make sure you have the Address Verification Service (AVS) matching turned off.  This will prevent swipes from passing and result in a declined transaction since no address is being passed.  Likewise, you may also want to turn off the CVV requirement to prevent a rejection.  Otherwise, you can enter the CVV number in the CVV form field prior to swiping the card. Also, make sure you properly order the expiration month and year and the first and last names, or your transaction will fail.</p>

<p>Happy parsing!</p>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/using-phps-preg_match-to-parse-credit-card-data-from-magnetic-swipe-readers/feed/</wfw:commentRss>
		</item>
		<item>
		<title>10 Steps to Capistrano and Plesk Subdomains Deployment</title>
		<link>http://thunderdata.com/blog/category/10-steps-to-capistrano-and-plesk-subdomains-deployment/</link>
		<comments>http://thunderdata.com/blog/category/10-steps-to-capistrano-and-plesk-subdomains-deployment/#comments</comments>
		<pubDate>Mon, 19 Jul 2010 17:56:22 +0000</pubDate>
		<dc:creator>Dawn</dc:creator>
		
		<category><![CDATA[Designer Showcase]]></category>

		<category><![CDATA[TDS Developer's Corner]]></category>

		<category><![CDATA[capistrano]]></category>

		<category><![CDATA[capistrano deployments]]></category>

		<category><![CDATA[rails]]></category>

		<category><![CDATA[rails tutorial]]></category>

		<category><![CDATA[subdomain]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=232</guid>
		<description><![CDATA[Plesk and Capistrano for subdomains is easily handled in this 10 step setup tutorial.]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve adopted a standard convention for deploying Rails apps that places the files in a subdomain of our clients&#8217; domains.  Since we use Plesk, there are some steps we have to take to get Capistrano deploys working.  Since we deploy a lot of apps, I decided to write this guide as much for the office as for anyone who may find it useful.  Let&#8217;s go through the steps:</p>

<ol>
<li>Create your subdomain in Plesk (ie. <em>myrailsapp</em>)</li>
<li>Navigate to the /domain.com<em>/subdomains/myrailsapp/conf</em> directory</li>
<li>Create a vhost.conf file.  Again, we use a convention that creates a new directory within <em>/myrailsapp</em> that holds our rails code.  Fittingly, we name the directory <em>/rails</em>.   The <em>DocumentRoot</em> points to the public directory of our application.  Enter the following into the <em>vhost.conf</em> file:</li>

<pre>
<code>DocumentRoot /var/www/vhosts/domain.com/subdomains/myrailsapp/rails/current/public 
RailsEnv production
</code>
</pre>

<li>If you haven&#8217;t already installed the capistrano and capistrano-ext (for multistage environments such as testing and production deploys), you&#8217;ll need to get them.  The <a href='http://www.capify.org/index.php/From_The_Beginning'>Capistrano tutorials</a> will walk you through that process.</li>
<li>With the gems installed, now we want to capify our code.  In your root rails app directory, enter the following command.  (You may have to sudo the command depending on your directory permissions.)</li>
<pre>
<code>capify .</code>
</pre>
<p>This will create two files:  <em>Capfile</em> and <em>deploy.rb</em> in your <em>/config</em> directory.</p>
<li>Open up your <em>deploy.rb</em> file and enter your configuration variables.  Again, you can refer to the <a href='http://www.capify.org/index.php/From_The_Beginning'>Capistrano tutorials</a> for help.  
<li>If you are only planning to deploy to a single environment, you&#8217;re work is done. If you plan a multi-stage environment, you&#8217;ll want to set the stages in your <em>deploy.rb</em> file and require the capistrano-ext gem like this:
<pre>
<code>set :stages, %w(testing, production)
set :default_stage, "testing"
require "capistrano/ext/multistage"
</code>
</pre>
<li>Within the /config directory, create a new <em>/deploy</em> directory and two new files, <em>testing.rb</em> and <em>production.rb</em>.  These files will provide the deploy details for each environment.
<li>Open up your new <em>.rb</em> files and enter the following for each environment:
<pre>
<code>
#############################################################
#   Application
#############################################################

set :application, "<strong style='color: black'>myrailsapp</strong>"
set :deploy_to, "<strong style='color: black'>/var/www/vhosts/domain.com/subdomains/myrailsapp/rails</strong>"

#############################################################
#   Settings
#############################################################

default_run_options[:pty] = true
ssh_options[:forward_agent] = true
set :use_sudo, true
set :scm_verbose, true
set :rails_env, "testing" 

#############################################################
#   Servers
#############################################################

set :user, "<strong style='color: black'>username</strong>"
set :password, "<strong style='color: black'>user_password</strong>"
set :domain, "<strong style='color: black'>myrailsapp.domain.com</strong>"
server domain, :app, :web
role :db, domain, :primary => true

#############################################################
#   Passenger
#############################################################

namespace :deploy do
  desc "Create the database yaml file"
  task :after_update_code do
    db_config = <<-EOF
    production:    
      adapter: mysql
      encoding: utf8
      username: <strong style='color: black'>database_username</strong>
      password: <strong style='color: black'>database_password</strong>
      database: <strong style='color: black'>database</strong>
      host: localhost
    EOF
    
    put db_config, "#{release_path}/config/database.yml"

  end
    
  # Restart passenger on deploy
  desc "Restarting mod_rails with restart.txt"
  task :restart, :roles => :app, :except => { :no_release => true } do
    run "touch #{current_path}/tmp/restart.txt"
  end
  
  [:start, :stop].each do |t|
    desc "#{t} task is a no-op with mod_rails"
    task t, :roles => :app do ; end
  end
  
end
</code>
</pre>

Then add the details of your repository for either subversion or git.
<pre>
<code>

#############################################################
#   GIT
#############################################################

set :scm, :git
set :branch, "<strong style='color: black'>master</strong>"
set :repository, "<strong style='color: black'>git@github.com:your_github_path/MYRAILSAPP.git</strong>"
set :deploy_via, :remote_cache
ssh_options[:forward_agent] = true

#############################################################
#   SVN
#############################################################

set :scm, :svn
set :branch, "<strong style='color: black'>trunk</strong>"
set :scm_user, '<strong style='color: black'>username</strong>'
set :scm_password, "<strong style='color: black'>user_password</strong>"
set :repository, Proc.new { "--username #{scm_user} --password '#{scm_password}' --no-auth-cache <strong style='color: black'>http://doman.com/path/to/your/subversion/repository/#{application}/trunk</strong>" } 

set :deploy_via, :remote_cache
ssh_options[:forward_agent] = true
</code>
</pre>
<li>That&#8217;s it; you&#8217;re ready to deploy.  Back at your terminal window, you&#8217;ll type the respective environment to which you&#8217;re deploy:</li>
</ol>

<pre>
<code>cap testing deploy</code>
</pre>

<p>A final note: make sure the user specified in your deploy files has permission to create directories on the server, otherwise your <em>/releases</em> directories will not be created.</p>

<p>Feel free to ask any questions if you&#8217;re having trouble with your Plesk subdomain and Capistrano deployment.  Good luck!</p>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/10-steps-to-capistrano-and-plesk-subdomains-deployment/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Rails validation error not displaying - validates_presence_of, error_message_for</title>
		<link>http://thunderdata.com/blog/category/rails-gotchas-validates_presence_on-error_message_for-display-failure/</link>
		<comments>http://thunderdata.com/blog/category/rails-gotchas-validates_presence_on-error_message_for-display-failure/#comments</comments>
		<pubDate>Thu, 07 Jan 2010 21:26:22 +0000</pubDate>
		<dc:creator>Dawn</dc:creator>
		
		<category><![CDATA[Newbie Rails Trip-ups]]></category>

		<category><![CDATA[TDS Developer's Corner]]></category>

		<category><![CDATA[error object redirect problem]]></category>

		<category><![CDATA[error validation failure]]></category>

		<category><![CDATA[errors do not display]]></category>

		<category><![CDATA[error_messages_on]]></category>

		<category><![CDATA[rails render versus redirect]]></category>

		<category><![CDATA[Rails validations]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[validate model]]></category>

		<category><![CDATA[validates_presence_on]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=174</guid>
		<description><![CDATA[Rails gotcha doesn't display validation errors when using redirects after validation execution.  Change the redirect to "render :action => 'method'" to handle error display.]]></description>
			<content:encoded><![CDATA[<p>I hit a wall recently as I tried to track down the reason <span style='font-family: Courier New;'> validates_presence_of </span> was not displaying errors.  Rails validations normally go off without a hitch, so I was a bit stumped when my attempts to save blank fields were not triggering the appropriate messages.  After ensuring my model and view were correct, I fired up the console to make sure my validations were working in the first place.  After loading an object and attempting a save, I checked to see if the errors object returned false.  Sure enough, all of the validations were enforced.</p>

<pre>
<code>
>> @contact = Contact.find_by_id(9)
=> #<Contact id: 9, user_id: 9, first_name: nil, middle: nil, last_name: nil, address: nil, apt_or_suite: nil, city: nil, state: nil, zip: nil, phone1: nil, phone2: nil, created_at: "2010-01-07 07:45:32", updated_at: "2010-01-07 07:45:32">
>> @contact.save
=> false
>> @contact.errors.empty?
=> false
>> @contact.errors.count
=> 6
>> @contact.errors.each_full { |msg| puts msg }
   City No blanks
   Zip No blanks
   First name No blanks
   Address No blanks
   Last name No blanks
   State No blanks
</code>
</pre>

<p>After more head banging, I was ready to give up with a simple notification workaround on the update method.</p>

<pre>
<code>
if !@contact.errors.empty?
  flash[:error] = "You are missing required fields."
  redirect_to edit_contact_url(@contact.user)
else
  flash[:notice] = "Successfully saved."
  redirect_to contact_url(@contact.user)
end
</code>
</pre>

<p>That works, but it doesn&#8217;t take advantage of the Rails&#8217; <span style='font-family: Courier New;'>error_messages_for</span> helper to display helpful messages and highlight problem fields.  Then I realized the initial error.  During redirects, the object&#8217;s data isn&#8217;t passed, so while the validations were enforced (the form data would not save upon submission), no errors were being output to the screen.  My new code rendered the page along with the error messages:</p>

<pre>
<code>
if !@contact.errors.empty?
  render :action =&gt; 'edit'
else
  flash[:notice] = "Successfully saved."
  redirect_to contact_url(@contact.user)
end
</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/rails-gotchas-validates_presence_on-error_message_for-display-failure/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Magnets in a Digital World: Credit Card Swipe Processing</title>
		<link>http://thunderdata.com/blog/category/magnets-in-a-digital-world-credit-card-swipe-processing/</link>
		<comments>http://thunderdata.com/blog/category/magnets-in-a-digital-world-credit-card-swipe-processing/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 19:37:31 +0000</pubDate>
		<dc:creator>gary</dc:creator>
		
		<category><![CDATA[Random Business Thoughts]]></category>

		<category><![CDATA[Team Dynamics]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=168</guid>
		<description><![CDATA[In a traditional store, paying by credit card involves swiping the card through a swipe machine, which reads the data stored on a credit card&#8217;s magnetic stripe.  The data includes a few key bits of information, namely:


    The account number and expiration date of the card
    The account holder&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>In a traditional store, paying by credit card involves swiping the card through a swipe machine, which reads the data stored on a credit card&#8217;s magnetic stripe.  The data includes a few key bits of information, namely:</p>

<ul>
    <li>The account number and expiration date of the card</li>
    <li>The account holder&#8217;s name</li>
    <li>Some provider-specific data for verification</li>
</ul>

<p>For a typical online transaction, the magnetic stripe on a card is not used.  Purchases are made by entering account information manually, along with verification values not found in the magnetic stripe.  This is acceptable for most people, as few computers come with magnetic card swipes.</p>

<p>However, what if someone wants to use an online system to run in-person transactions?  With ThunderTix, many of our clients use our system for ticket sales on site.  Typing every bit of data for each customer is slow, and tends to make people in line cranky.  Fortunately, the magnetic stripe comes to our rescue.  The first part of a magnetic stripe&#8217;s data looks something like this:</p>

<p><code>%Bxxxxxxx^LASTNAME/FIRSTNAME ^yymmzzzzzzzzzzzzzzz?</code><br /></p>

<p>where the</p>

<p><code>xxxxxxx</code><br  /></p>

<p>is an account number,</p>

<p><code>LASTNAME/FIRSTNAME</code><br  /></p>

<p>are the account holder&#8217;s name,</p>

<p><code>yymm</code><br /></p>

<p>is the expiration date, and</p>

<p><code>zzzzzzzzzz</code><br /></p>

<p>is additional numbers.  Using the standard format to detect a card swipe transaction, we can extract this information to expedite order processing:</p>

<p><code>
if credit_card_number =~ /^%B(.)*?$/<br />
card_fields = params[:cc][:number][2..-1].split(&#8217;^')<br />
card_number = card_fields[0]<br />
name = card_fields[1].strip.split(&#8217;/')<br />
first_name = name[0]<br />
last_name = name[1]<br />
expiration_year = card_fields[2][0,2]<br />
expiration_month = card_fields[2][2,2]<br />
end<br />
</code></p>

<p>A few bits of additional data (magnetic stripes do not contain the verification values used for online transactions), and we&#8217;ve managed to cut each patron&#8217;s wait time significantly.</p>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/magnets-in-a-digital-world-credit-card-swipe-processing/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Marketing in Down Times</title>
		<link>http://thunderdata.com/blog/category/marketing-in-down-times/</link>
		<comments>http://thunderdata.com/blog/category/marketing-in-down-times/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 15:01:54 +0000</pubDate>
		<dc:creator>Dawn</dc:creator>
		
		<category><![CDATA[Random Business Thoughts]]></category>

		<category><![CDATA[budget]]></category>

		<category><![CDATA[consumers]]></category>

		<category><![CDATA[economy]]></category>

		<category><![CDATA[effective advertising]]></category>

		<category><![CDATA[effective marketing]]></category>

		<category><![CDATA[marketing]]></category>

		<category><![CDATA[marketing in a down economy]]></category>

		<category><![CDATA[marketing in a tough economy]]></category>

		<category><![CDATA[tropican orange juice]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=142</guid>
		<description><![CDATA[I&#8217;m always pleasantly surprised when I stumble upon the result of a company&#8217;s marketing efforts and realize how perfectly they succeeded in directing their message.  My favorite,  a television ad campaign for Prego, used music to drive home the old-world style of their spaghetti sauce and succeeded beautifully.

In yesterday&#8217;s NY Times section on [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m always pleasantly surprised when I stumble upon the result of a company&#8217;s marketing efforts and realize how perfectly they succeeded in directing their message.  My favorite, <a href='http://thunderdata.com/blog/category/getting-it-right/'> a television ad campaign for Prego</a>, used music to drive home the old-world style of their spaghetti sauce and succeeded beautifully.</p>

<p><a href='http://www.nytimes.com/2009/01/08/business/media/08adco.html'>In yesterday&#8217;s NY Times section on advertising,</a> the article focused on Tropicana orange juice.  Included with the piece was an ad image containing Tropicana&#8217;s new tag line along with a plain-jane carton of &#8220;store brand&#8221; OJ.   At a glance, I assumed Tropicana was positioning their orange juice as a cut above the generic store brand.  It was only upon reading the article that I recognized the simple carton design was actually Tropicana&#8217;s adopted new look&#8211;replacing the old straw and orange logo.  Why would they choose such a simple carton?  To appeal to budget conscious consumers.</p>

<p><img src='http://graphics8.nytimes.com/images/2009/01/08/business/08adco01-600.jpg' width='470' height='137'></p>

<p>Interestingly, Tropicana&#8217;s full brand name includes the words, &#8220;Pure Premium&#8221;.  Coming at a time when buyers are eschewing luxury items, Tropicana needed to downplay &#8220;premium&#8221; without sacrificing their brand association with quality .  The carton is an effective messenger.  Throw in the cute new screw cap that&#8217;s shaped like half an orange, and Tropicana is poised to retain its 40% market share&#8211;even as shoppers trim their budgets.  That&#8217;s effective marketing!</p>

<p><img src='http://www.thunderdata.com/uploads/Main/oj2.jpg' align='center'></p>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/marketing-in-down-times/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Can Management Understand Employee Needs?</title>
		<link>http://thunderdata.com/blog/category/can-management-understand-employee-needs/</link>
		<comments>http://thunderdata.com/blog/category/can-management-understand-employee-needs/#comments</comments>
		<pubDate>Sat, 30 May 2009 04:40:47 +0000</pubDate>
		<dc:creator>Dawn</dc:creator>
		
		<category><![CDATA[Team Dynamics]]></category>

		<category><![CDATA[developer relationships]]></category>

		<category><![CDATA[disparage employer]]></category>

		<category><![CDATA[employee roles]]></category>

		<category><![CDATA[interpersonal relationships]]></category>

		<category><![CDATA[leadership]]></category>

		<category><![CDATA[management]]></category>

		<category><![CDATA[management relationships]]></category>

		<category><![CDATA[success]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=98</guid>
		<description><![CDATA[During a conversation with a large national client, two of their staff members made the implication that their &#8220;boss&#8221;, the executive director, was out of touch with what was going on in the trenches, and he should not be consulted on important decisions.   Though I agree that the director may be unaware of the day-to-day [...]]]></description>
			<content:encoded><![CDATA[<p>During a conversation with a large national client, two of their staff members made the implication that their &#8220;boss&#8221;, the executive director, was out of touch with what was going on in the trenches, and he should not be consulted on important decisions.   Though I agree that the director may be unaware of the day-to-day minutiae of staff work, as the person who signs the check that pays me, the director&#8217;s feedback from a high level was important to us.  When I hung up the phone, I asked my office why such a common misconception existed&#8211;an employee&#8217;s belief that management lacks an understanding of their work?</p>

<p>Bad managers do exist, but the vast majority of my clients have exceptional leaders&#8211;including the aforementioned director.  Most are intimately aware of the roles their employees play in their success. A good manager shouldn&#8217;t have to know the details of an employee&#8217;s job; inherent in any position is a trust that sound decisions are best made within one&#8217;s area of expertise. Those organizations are profitable, successful, and forward thinking businesses indicating a healthy understanding of the roles of their staff.</p>

<p>As a business owner, I also allow a certain latitude within an employee&#8217;s job. Our web sales is efficiently handled without my input; <a href='http://thundertix.com'>ThunderTix</a> has been cultivated under anothers purview; and our programmers would not benefit from my code reviews. WIth them, I have been pleased to see growth in our sales and profitability each year of our eight year history.  But watching over those financial markers does not translate into an all-encompassing focus on the bottom line or lack of insight into my employees&#8217; respective roles.</p>

<p>Yet I and our executive director share something in common. Despite our efforts, our employees have both publicly disparaged our leadership. A former employee wrote:</p>

<blockquote>Someone running a business isn’t as focused on the institution.  To generalize, their primary focus is simply on generating money.</blockquote>

<p>That&#8217;s a pretty haughty generalization from someone who has not walked in the shoes of a business owner.   The fact is, most company leaders are focused on a whole lot more than generating money.   For us here at Thunder Data, a primary driver of our own success lies in <a href='http://thunderdata.com/blog/category/changing-course-team-priorities-and-client-relationships/'>client satisfaction and responsiveness</a>, and it is the single <a href='http://thunderdata.com/blog/category/getting-it-done-faster-better/'>most lauded trait</a> we hear in feedback from clients.   And in what I&#8217;ve hoped was a demonstration of my understanding of employee needs, I&#8217;ve been proud of the fact that I&#8217;ve not been afraid to let my people test the waters with new languages, products or processes to help feed their collective hunger for staying on top of the latest trends in tech. </p>

<p>One of my goals this year is to expand employee decision making while balancing with client expectations.   It requires mutual trust and respect of what each of us brings to the table. When we recognize an individual&#8217;s role, we&#8217;ll succeed individually and collectively.</p>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/can-management-understand-employee-needs/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Altering Course: Development Team and Client Relationships</title>
		<link>http://thunderdata.com/blog/category/changing-course-team-priorities-and-client-relationships/</link>
		<comments>http://thunderdata.com/blog/category/changing-course-team-priorities-and-client-relationships/#comments</comments>
		<pubDate>Thu, 21 May 2009 04:53:08 +0000</pubDate>
		<dc:creator>Dawn</dc:creator>
		
		<category><![CDATA[Team Dynamics]]></category>

		<category><![CDATA[agile practices]]></category>

		<category><![CDATA[agile programming environment]]></category>

		<category><![CDATA[client relationships]]></category>

		<category><![CDATA[programmers and project manager relations]]></category>

		<category><![CDATA[scrum]]></category>

		<category><![CDATA[team environment]]></category>

		<category><![CDATA[team programming]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=87</guid>
		<description><![CDATA[Today, we received a client request to improve a page&#8217;s load time while in the midst of making major aesthetic improvements to another site.  When I suggested we switch gears to help the client, I was met with resistance in the form of frustration that the new project was being interrupted.

This gave us opportunity to [...]]]></description>
			<content:encoded><![CDATA[<p>Today, we received a client request to improve a page&#8217;s load time while in the midst of making major aesthetic improvements to another site.  When I suggested we switch gears to help the client, I was met with resistance in the form of frustration that the new project was being interrupted.</p>

<p>This gave us opportunity to have a long overdue discussion that probably would not have taken place if we hadn&#8217;t had recent staff changes to our programming team.   The crux of our talk:  our recent past will not dictate our future.</p>

<p>For the last year, we have followed agile development practices that offered remarkable improvements to how we scheduled and executed work.   Though the scrum master&#8217;s philosphies dramatically differed from my own, I  allowed a fundamental shift in how we operated our business.  The biggest change lay in our responsiveness to client requests for bug fixes and improvements which were increasingly  pushed to the back burner so as not to disrupt weekly sprints or programmers who were &#8220;in the flow&#8221;.</p>

<p>At some point, I began to realize that the way we practiced agile centered on how we could keep the development team happy.   But they weren&#8217;t happy.  And neither were the project managers.  Worse, our clients were not getting the attention to which they were accustomed and deserved.</p>

<p>Despite my knowledge that our practices were not benefitting our business or clients, in lettng the programming team to dictate our business process, I was essentially allowing the tail to wag the dog.  It was during one sprint meeting when I asked a question that I got my wake-up call.  Why, I asked, are we focused on how we could improve the programmers&#8217; jobs, but no one is interested in how to improve our jobs as the primary contacts to the customer?</p>

<p>The answer was telling:  &#8221;We don&#8217;t even know what you do.&#8221;</p>

<p>So this morning, we talked about change to our collective mindset.  I explained that I meet with a group of professional women every six weeks.  Virtually all of them have fallen victim to the recent economic climate.  Separately, two of the women indicated that we must be doing something right:  in their minds, we seemed to stand apart as a business that is profitable and growing despite the downturn.</p>

<p>I told the staff that our success didn&#8217;t happen by chance.  Before this past year, we&#8217;d put our clients first.   Today, I stood firm:  from here on out, we stand second to our clients.  If they are our priority, we cannot help but succeed.   The cool thing is, they will, too.</p>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/changing-course-team-priorities-and-client-relationships/feed/</wfw:commentRss>
		</item>
		<item>
		<title>RailsConf Retrospectives, Part 1: Testing</title>
		<link>http://thunderdata.com/blog/category/railsconf-retrospectives-part-1-testing/</link>
		<comments>http://thunderdata.com/blog/category/railsconf-retrospectives-part-1-testing/#comments</comments>
		<pubDate>Mon, 11 May 2009 18:27:44 +0000</pubDate>
		<dc:creator>gary</dc:creator>
		
		<category><![CDATA[TDS Developer's Corner]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=76</guid>
		<description><![CDATA[The Thunder Data dev team was represented at this year&#8217;s RailsConf in Las Vegas, and we learned quite a bit.  We&#8217;re starting a series of RailsConf Retrospectives to delve into some of the topics covered at the conference.

Testing

One of the most pervasive themes at RailsConf was that of testing and Test-Driven Design, principles that have [...]]]></description>
			<content:encoded><![CDATA[<p>The Thunder Data dev team was represented at this year&#8217;s RailsConf in Las Vegas, and we learned quite a bit.  We&#8217;re starting a series of RailsConf Retrospectives to delve into some of the topics covered at the conference.</p>

<h3>Testing</h3>

<p>One of the most pervasive themes at RailsConf was that of testing and Test-Driven Design, principles that have been embraced in the Rails community for good reason.  When done properly, TDD yields a suite of automated tests that can be run at any time to ensure the integrity and production readiness of an application.  But what exactly is testing, and how does it yield such boons?</p>

<h3>Red-Green-Refactor</h3>

<p>The essence of TDD is the cycle of Red-Green-Refactor.  Start by writing a high-level test describing a bit of functionality that fails, write code until it passes, and then clean up and improve the code.  This continuous cycle results in not only cleaner, more robust code, but by its very nature produces a set of tests that describe the entire functionality and operation of the application as a whole.  This process also forces tests to be written and debugged first, so that any errors later can be properly attributed to the application code, not the tests.  At the end, you will have a test suite that both defines and monitors the functionality of the application.</p>

<h3>Fixing It Up</h3>

<p>What happens when it comes time to rewrite that particularly nasty controller?  With TDD, have no fear!  If an application has a good set of tests, refactoring is a snap.  Simply make whatever changes you need and rerun the test suite.  If everything comes back green, you may proceed.  If not, track down the failing tests and fix the application code that is causing failure.  Over the lifespan of an application, a comprehensive set of tests for general use and edge cases alike will allow for any future development on any particular part to proceed without a hitch.</p>

<p>Stay tuned for more articles as we continue our RailsConf Retrospectives series.</p>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/railsconf-retrospectives-part-1-testing/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Fixing a Dysfunctional Team</title>
		<link>http://thunderdata.com/blog/category/fixing-a-dysfunctional-team/</link>
		<comments>http://thunderdata.com/blog/category/fixing-a-dysfunctional-team/#comments</comments>
		<pubDate>Tue, 17 Mar 2009 03:00:05 +0000</pubDate>
		<dc:creator>Dawn</dc:creator>
		
		<category><![CDATA[Team Dynamics]]></category>

		<category><![CDATA[agile team development]]></category>

		<category><![CDATA[cats and dogs]]></category>

		<category><![CDATA[developer relationships]]></category>

		<category><![CDATA[dysfunctional team]]></category>

		<category><![CDATA[human resources]]></category>

		<category><![CDATA[programmers and project manager relations]]></category>

		<category><![CDATA[software development]]></category>

		<guid isPermaLink="false">http://thunderdata.com/blog/?p=79</guid>
		<description><![CDATA[Every Monday morning our team engages in a sprint planning meeting.  Starting with a retrospective of the prior week, we discuss problems, successes, and ideas from individually posted notes on each topic  Intended to be frank discussions, we are openly enthusiastic about the good things that occur, but our challenges and frustrations are generally veiled.  [...]]]></description>
			<content:encoded><![CDATA[<p>Every Monday morning our team engages in a sprint planning meeting.  Starting with a retrospective of the prior week, we discuss problems, successes, and ideas from individually posted notes on each topic  Intended to be frank discussions, we are openly enthusiastic about the good things that occur, but our challenges and frustrations are generally veiled.  The goals of a retrospective aim to improve the team&#8217;s flow, but if we aren&#8217;t honest about the challenges we&#8217;re facing, they are simply a waste of time.</p>

<p>During a retrospective six weeks ago, my Post-it note read:  “We are a dysfunctional team.”</p>

<p>For a couple of weeks, I felt frustrated and unhappy with the office atmosphere.  No one was complaining, work was getting completed, and there was no list of dissatisfying issues.  But there was a palpable sense of unhappiness among the team.  My posted note opened a long closed Pandora&#8217;s box, and so began our first real steps to re-creating the team.</p>

<p>We are not alone.</p>

<p>At SXSW, no less than four panels tossed around the subject of developer/staff relationships.  The consistency of the theme was surprising.  Two questions begged answers:  what factors lend themselves to these difficult relationships, and how do we change team dynamics?  I was on a quest to find answers and work on fixing our own team.</p>

<p>To start, we discussed what we collectively felt were the primary requirements of a &lt;i&gt;functional&lt;/i&gt; team: trust, honesty, partnership, and commitment.  We were failing at all of them, and the negative pall cast on the office was tangible.</p>

<p>Each month, we&#8217;ll share the changes made and the results realized as we attempt to overcome the obstacles that prevent us from realizing our potential</p>
]]></content:encoded>
			<wfw:commentRss>http://thunderdata.com/blog/category/fixing-a-dysfunctional-team/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

