<?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:wfw="http://wellformedweb.org/CommentAPI/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    
    <title>Parker Smith Software Blog</title>
    <link>http://www.parkersmithsoftware.com/blog</link>
    <description>The latest news, random thoughts, and some helpful tech talk from Parker Smith, a software company in Louisville, KY.</description>
    <language>en-us</language>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/parkersmith" /><feedburner:info uri="parkersmith" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
      <title>Our billing address has changed</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/jZsXSYt_304/35-our-billing-address-has-changed</link>
      <description>
<![CDATA[As many of our clients already know we operate a virtual office, but we still have to have a billing address. &nbsp;We're using this blog post to let people know that our billing address has change...]]>      </description>
      <content:encoded>
<![CDATA[<p>As many of our clients already know we operate a virtual office, but we still have to have a billing address. &nbsp;We're using this blog post to let people know that our billing address has changed. &nbsp;The new address is:</p>
<p>&nbsp;</p>
<p>Parker Smith Software<br />
3133 Brownsboro Rd.&nbsp;<br />
Louisville, KY 40206</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/35-our-billing-address-has-changed</guid>
      <pubDate>Mon, 04 Apr 2011 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/35-our-billing-address-has-changed</feedburner:origLink></item>
    <item>
      <title>update remote system password w/ Ruby over SSH</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/gFFhe-1xaa4/34-update-remote-system-password-w--ruby-over-ssh</link>
      <description>
<![CDATA[&nbsp;I was working on some code for our server hosting system last night and I needed a way to execute commands on a remote system's console. &nbsp;My actual use case is a bit more complicated sin...]]>      </description>
      <content:encoded>
<![CDATA[<p>&nbsp;I was working on some code for our server hosting system last night and I needed a way to execute commands on a remote system's console. &nbsp;My actual use case is a bit more complicated since I'm sending commands to a Xen Virtual Server console where SSH may not be enabled (ssh-ing into the host) but I thought this would be a good start.</p>
<p>You can send commands to a remote host using SSH alone as shown <a target="_blank" href="http://parkersmithsoftware.com/blog/post/17-remote-execution-of-commands-via-ssh">here</a>, but since this is an interactive console session I used ruby to listen for the console prompts and enter the correct response. &nbsp;See below:</p>
<p>&nbsp;</p>
<script src="https://gist.github.com/796628.js"> </script>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/34-update-remote-system-password-w--ruby-over-ssh</guid>
      <pubDate>Wed, 26 Jan 2011 00:00:00 -0500</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/34-update-remote-system-password-w--ruby-over-ssh</feedburner:origLink></item>
    <item>
      <title>Debugging a function 'caller' in AS3</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/k9_bIba3dGc/33-debugging-a-function--caller--in-as3</link>
      <description>
<![CDATA[&nbsp;So I was recently trying to track down a bug in an Adobe AIR application that we've been working on for the past year. &nbsp;Needless to say the application is pretty big and I had isolated t...]]>      </description>
      <content:encoded>
<![CDATA[<p>&nbsp;So I was recently trying to track down a bug in an Adobe AIR application that we've been working on for the past year. &nbsp;Needless to say the application is pretty big and I had isolated the bug to a particular function. &nbsp;The problem is that I needed to know what other function was calling it when the error was being encountered and that could have been a couple dozen locations. &nbsp;</p>
<p>Here's a nice little code snippet that I placed in the buggy function to see who was calling it:</p>

<code:javascript>

var stackTrace:String;

try { throw new Error(); }
catch (e:Error) { stackTrace = e.getStackTrace(); }

var lines:Array = stackTrace.split("\n");
var isDebug:Boolean = (lines[1] as String).indexOf('[') != -1;

var path:String;
var line:int = -1;

if(isDebug)
{
	var regex:RegExp = /at\x20(.+?)\[(.+?)\]/i;
	var matches:Array = regex.exec(lines[2]);
	
	path = matches[1];
	
	//file:line = matches[2]
	//windows == 2 because of drive:\
	line = matches[2].split(':')[2];
}
else
{
	path = (lines[2] as String).substring(4);
}

trace("\n\n\nmyFunction(" + $animTime + ", " + $scaleMultipler + ", " + (($options == null)? "options=null" : "options={...}" )  + ");");
trace("myFunction caller: " + path + (line != -1 ? '[' + line.toString() + ']' : '') + "\n\n\n");

</code>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/33-debugging-a-function--caller--in-as3</guid>
      <pubDate>Thu, 13 Jan 2011 00:00:00 -0500</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/33-debugging-a-function--caller--in-as3</feedburner:origLink></item>
    <item>
      <title>Regex find and replace</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/OMxC40B-Px8/32-regex-find-and-replace</link>
      <description>
<![CDATA[I&nbsp;was recently working on an Adobe AIR project (using AS3 programming language &amp; Flash Builder aka Eclipse as the editor) and I&nbsp;needed to do a major re-factor of some code in a lot of...]]>      </description>
      <content:encoded>
<![CDATA[<p>I&nbsp;was recently working on an <a target="_blank" href="http://www.adobe.com/products/air/">Adobe AIR</a> project (using <a target="_blank" href="http://en.wikipedia.org/wiki/ActionScript">AS3 programming language</a> &amp; <a target="_blank" href="http://www.adobe.com/products/flashbuilder/">Flash Builder</a> aka <a target="_parent" href="http://eclipse.org">Eclipse</a> as the editor) and I&nbsp;needed to do a major re-factor of some code in a lot of different places.&nbsp; I decided to do a <a target="_blank" href="http://en.wikipedia.org/wiki/Regular_expression">regular expression</a> find and replace.&nbsp; After doing some experimentation on <a target="_blank" href="http://rubular.com">Rublar</a> (with Ruby code) I was able to hone my regex to match correctly, but I found a few variations with how different programs do regex find and replace.&nbsp; Here's the info:</p>
<p><br />
<br />
1) This is our test string:<br />
<p>MyStaticClass.randomMethod().someFunction( BlahClass.MY_CONSTANT ).addEventListener</code><br />
<p>which we want to find and replace to be this:</p>
<p>(MyStaticClass.randomMethod().someFunction(BlahClass.MY_CONSTANT) as MyNewClass).genericObject.addEventListener</code>
<br />
2) This is the full regex notation (which I was test matching in ruby):&nbsp; </p>
<p><p>/^MyStaticClass\.randomMethod\(\)\.someFunction\((.+)\).addEventListener$/x</code><br />
<br />
With this regex there is 1 match capture:&nbsp; BlahClass.MY_CONSTANT.&nbsp; You can use the various captures in a replacement string by providing the replacement string but inserting $X where you want the capture inserted, and where &quot;X&quot; is the capture instance, so in this case it is $1.<br />
<br />
I was able to do a regex find and replace in TextMate like this:<br />
<br />
Find: </p>
<p><p>^MyStaticClass\.randomMethod\(\)\.someFunction\((.+)\).addEventListener$</code></p>
<p><br />
Replace: </p>
<p><p>(MyStaticClass.randomMethod().someFunction($1) as MyNewClass).genericObject.addEventListener</code></p>
<p>However no such luck in Flash Builder.&nbsp; After some messing around I found out that Eclipse doesn't want the beginning and end line notations, so THIS works in Eclipse:<br />
<br />

Find:&nbsp; </p>
<p>MyStaticClass\.randomMethod\(\)\.someFunction\((.+)\).addEventListener</code>

<p>Replace: </p>
<p>(MyStaticClass.randomMethod().someFunction($1) as MyNewClass).genericObject.addEventListener</code>
]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/32-regex-find-and-replace</guid>
      <pubDate>Tue, 26 Oct 2010 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/32-regex-find-and-replace</feedburner:origLink></item>
    <item>
      <title>Web Hosting Explained</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/VS2Wp-t-1Hg/31-web-hosting-explained</link>
      <description>
<![CDATA[What is this &quot;hosting&quot; anyway?
Wikipedia says:&nbsp;&quot;Web hosting is a service that allows individuals and organizations to make their own website available via the World Wide Web&qu...]]>      </description>
      <content:encoded>
<![CDATA[<p>What is this &quot;hosting&quot; anyway?</p>
<p>Wikipedia says:&nbsp;&quot;Web hosting is a service that allows individuals and organizations to make their own website available via the World Wide Web&quot;.&nbsp; Basically if you want to have your website online you need to put it somewhere that people can get to it, this is always going to be on a server connected to the internet.</p>
<p>The scope of hosting service varies widely but can generally be classified into 3 groups:&nbsp; Shared Hosting, Virtual Private Server (VPS) Hosting, and Dedicated Server Hosting.</p>
<p><strong>Shared Hosting</strong><br />
In a shared hosting environment there are multiple websites all sharing the same resources, often there will be 1 server hosting hundreds of simple websites.&nbsp; The advantage to this is that cost can be decreased because you are sharing resources with other people.&nbsp; The disadvantage here is that you are essentially overselling those resources again and again.&nbsp; If any 1 of the websites on the shared server starts using more resources (for example if they have a traffic increase) all the other sites have less available.&nbsp; So your site could be really slow someday because someone else is getting a lot of traffic.</p>
<p><strong>Dedicated Server Hosting</strong><br />
With a dedicated server it is pretty much just like it sounds. You have your own physical server that is designated for your use only.&nbsp; You have complete utilization of all the machines resources from processing power, and memory to hard drive space, no other websites will share the server unless they are yours and you want that.&nbsp; Sometimes you will purchase the hardware yourself outright and other times you'll lease it from the hosting provider.&nbsp; Generally it is better to lease because the hosting provider will maintain the hardware and replace parts if they go bad.&nbsp; The advantage of a dedicated server is that you have all the power of a single machine to yourself.&nbsp; The disadvantage lies in hardware failure.&nbsp; If a hard drive or power supply goes out or some other mechanical failure happens your server could go down until the hardware is repaired, in best case scenarios this can often be 24-48 hours and hopefully the failure didn't cause any data loss.&nbsp; It is possible to get servers that have redundant hard drives and other parts to have a failsafe against hardware failure, but those servers are much more expensive.</p>
<p><strong>Virtual Private Server (VPS) Hosting</strong><br />
VPS&nbsp;hosting is somewhat of a mix between Shared and Dedicated taking all the good parts and few if none of the bad.&nbsp; The process of VPS&nbsp;hosting is based on a technology called &quot;Virtualization&quot; in which the resources of a host machine are divided amongst many virtual machines which run on the host.&nbsp; The host machines are often very high end powerful servers that would be overkill for use as a Dedicated Server, however through virtualization you can essentially have multiple dedicated servers by dividing the resources.</p>
<p>VPS&nbsp;hosting doesn't suffer from the same disadvantages as Shared Hosting because with a VPS the resources are fixed.&nbsp; If a VPS is given 1 Gigabyte of memory it is there for it to use and restricted from others even if it only ever uses 1/4 of that.</p>
<p>Hardware upgrades are a significant advantage with a VPS.&nbsp; If the processing power, memory or storage space needs to be increased it only takes a few clicks and it is done.&nbsp; With Dedicated servers the hardware must be bought, information copied over if necessary, the server must be shut down, hardware installed and the brought back up for any post installation tasks.&nbsp;</p>
<p>Some people might be thinking right about now &quot;don't the host machines need hardware maintenance sometimes too?&quot;&nbsp; The answer is yes, but through a technology called &quot;Live Migration&quot; the virtual machines can be moved from one host to another without any down time.&nbsp; This makes maintenance on the hosts realy easy.</p>
<p>Another advantage of a VPS&nbsp;is the setup time.&nbsp; With a dedicated server you need to order the machine, then install all the software and lastly install the physical machine into the data center and connect it to the internet.&nbsp; With a VPS they can be setup from &quot;templates&quot; wich include all the necessary software and configurations, and because the amount of memory and disk space is just a setting a new VPS can be setup in mere minutes.</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/31-web-hosting-explained</guid>
      <pubDate>Wed, 06 Oct 2010 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/31-web-hosting-explained</feedburner:origLink></item>
    <item>
      <title>What is Ruby On Rails for the non-programmer</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/gexRC1Dh20s/30-what-is-ruby-on-rails-for-the-non-programmer</link>
      <description>
<![CDATA[(related: Language vs. Framework,&nbsp; Hosting Explained: What is Shared vs. VPS vs. Dedicated)

Intro
At Parker Smith we build a lot of web applications and web sites, and in doing that we cre...]]>      </description>
      <content:encoded>
<![CDATA[<p>(related: Language vs. Framework,&nbsp; Hosting Explained: What is Shared vs. VPS vs. Dedicated)<br />
<br />
<strong>Intro</strong><br />
At Parker Smith we build a lot of web applications and web sites, and in doing that we create 90% of those web projects using a software development framework called Ruby On Rails.&nbsp; I thought I'd take a minute to explain exactly what that is and why we work with it.<br />
<br />
<br />
<strong>Basics</strong><br />
Ruby on Rails is a &quot;full stack web development framework&quot;, this means that it was specifically created for developing web projects and has many of the common tasks required for creating a web application already built in.&nbsp; Additionally the core programming language, Ruby, is very easy to work with, so the end result is that a web application can be developed much faster, anywhere from 3-5x faster depending on the web development language or framework your comparing it to.&nbsp; This translates into a lower cost of development when building a project with Rails.&nbsp; <br />
<br />
<br />
<strong>Open Source</strong><br />
The Rails framework is open source and free, that means anyone can get it and see the inner-workings of how it is put together, and even modify that if they see fit (note this is the source code of the rails framework we're talking about, not a custom developed application built on top of rails).&nbsp; It also means that there are thousands upon thousands of developers all across the world looking at how the Rails framework is built and contributing new features as well as updating existing ones.&nbsp; <br />
<br />
This is in contrast to proprietary development frameworks where a corporation keeps the source code locked down under proprietary copyrights.&nbsp; In those circumstances a development team may need to make the application work in ways that the framework&nbsp; does not allow, or perhaps they've even found an error in the framework itself.&nbsp; With proprietary closed-source frameworks they are just out of luck, unless the corporate gate keeper decides to issue an update for everyone using the framework. However with Rails developers can just change the framework's source code to work how they need it to.<br />
<br />
<br />
<strong>Supportability</strong><br />
Ruby on Rails is built to support industry best practices, with this it has the &quot;application architecture&quot; built in.&nbsp; This means that the Rails community as a whole has come together and said that 99% of web applications built in Rails should use the default structure, this makes it incredibly easy for a developer to get up to speed on an existing Rails project, because he/she will know exactly how everything should work, and where everything is located.&nbsp; This is a stark contrast to other frameworks or languages where it can sometimes take weeks or months for a new development team to understand the inner-workings of an existing application.&nbsp; Because all these best practices are built-in to every Rails application it means that you are not held hostage with the company that built your application, you could take your code to anyone that does Rails development and they should be able to get up to speed adding features and making updates in no time.<br />
<br />
<br />
<strong>Scalability</strong><br />
Scalability referrers to how easily an application can handle an increase in traffic, increase in database size,&nbsp; and growth for the application to be spread out across multiple servers.&nbsp; Rails has proven it's scalability with some of the internet's largest sites built on Rails such as twitter.com, scribd.com, hulu.com, yellowpages.com.&nbsp; Additionally some pretty large and reputable organizations use Rails for both internal and external applications including: Amazon.com, BBC, Cisco, C-Net, Electronic Arts, IBM, JP Morgan, NASA, Oracle, Oakley, Siemens, Yahoo!, New York Times, Orbitz, Google, Turner Media and many others.<br />
<br />
<strong><br />
Hosting a Rails Application</strong><br />
Some may argue that a rail application is more expensive to host than an application developed in another language, and for some languages this is true for others it is not, the primary case in question here is a &quot;shared&quot; hosting environment vs. a &quot;virtual private server&quot; (VPS) or dedicated server.&nbsp; <br />
<br />
For best performance a Rails application should almost always be hosted on its own VPS.&nbsp; With Rails whatever increased cost you may see with hosting will be offset exponentially by the increased development time.&nbsp; A software developer's hourly rate is almost always going to be much more expensive than even some of the most elaborate hosting environments.&nbsp; Thus it makes more sense to pay much less for an application built in Rails and pay a tiny bit more for hosting.&nbsp; In situations where 2 applications built with competitive development frameworks and are both hosted on a VPS, you're comparing apples to apples.&nbsp; If the size and power of the VPS is the same the only difference is the cost to develop each application.<br />
<br />
<br />
<strong>Closing</strong><br />
Ultimately in software development a programming framework is just a tool that allows you to complete a task, the value of the tool lies in how much more efficient and flexible it makes you.&nbsp; With Rails as a foundation we can build a software and make it work in any way we want, thus we are completely in control, are not stuck working within the constructs of how someone else thought we should be working.&nbsp; <br />
<br />
The real truth is that most programmers don't love programming (the act of actually writing out the code) what they enjoy is building things with their own two hands, and watching that grow, watching their work enrich the lives of their clients. Developers who use Rails are so passionate about it because it makes that building process so much faster and easier.&nbsp; If you found a carpenter who had a saw that would cut, sand, assemble, and stain wood for chairs, all on its own (because those are common tasks for chair building), I bet he'd be pretty excited about that saw too.</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/30-what-is-ruby-on-rails-for-the-non-programmer</guid>
      <pubDate>Sun, 12 Sep 2010 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/30-what-is-ruby-on-rails-for-the-non-programmer</feedburner:origLink></item>
    <item>
      <title>Programming languages vs frameworks</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/dlHU49fLELc/29-programming-languages-vs-frameworks</link>
      <description>
<![CDATA[In the world of software these two terms are sometimes confused, Wikipedia tells us that &quot;a programming language is an artificial language designed to express computations that can be performe...]]>      </description>
      <content:encoded>
<![CDATA[<p>In the world of software these two terms are sometimes confused, Wikipedia tells us that &quot;a <a href="http://en.wikipedia.org/wiki/Programming_language">programming language</a> is an artificial language designed to express computations that can be performed by a machine, particularly a computer&quot;.&nbsp; A programming framework on the other hand is a collection of commonly used libraries and methodologies for creating computer software.&nbsp; Many common tasks are built into the framework so you don't need to create them from scratch.</p>
<p>Using a programming framework allows you to develop software much faster because many of the common routines are built-in.&nbsp; For example in web based software you will routinley need to access information stored in a database.&nbsp; If you were writing the code from scratch you would need to figure out how to connect to and ask questions of the database, maybe even how you would handle errors.&nbsp; In a web based development framework you would probably have a code library that handles all those functions which could be reused for each project.&nbsp; Thus you'd save a lot of time because you wouldn't be writing the same code over and over.</p>
<p>Some common web development languages:</p>
<ul>
    <li>Ruby</li>
    <li>PHP</li>
    <li>ASP</li>
    <li>C#</li>
    <li>VB</li>
    <li>Java</li>
</ul>
<p>Some common web development frameworks:</p>
<ul>
    <li>Ruby on Rails (Ruby)</li>
    <li>Code Igniter (PHP)</li>
    <li>CakePHP (PHP)</li>
    <li>ASP.NET (C#, VB and others)</li>
    <li>JSP (Java)</li>
    <li>JSF (Java)</li>
</ul>
<p>&nbsp;</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/29-programming-languages-vs-frameworks</guid>
      <pubDate>Sat, 11 Sep 2010 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/29-programming-languages-vs-frameworks</feedburner:origLink></item>
    <item>
      <title>Website vs Web Application</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/B7bmaQb3E8U/28-website-vs-web-application</link>
      <description>
<![CDATA[Sometimes people ask what the difference is between a &quot;website&quot; and a &quot;web application&quot;?
Generally speaking now days most all websites are also web applications.&nbsp; However ...]]>      </description>
      <content:encoded>
<![CDATA[<p>Sometimes people ask what the difference is between a &quot;website&quot; and a &quot;web application&quot;?</p>
<p>Generally speaking now days most all websites are also web applications.&nbsp; However a website that is just a website would be one that is &quot;static&quot; meaning that it doesn't do anything, it's pages are simply like those of a magazine, once they are created and put online they are the same every time you look at them.</p>
<p>A web application on the other hand has some kind of logic built in that does something, perhaps changing the content of a page when it is requested depending on certain factors.&nbsp; This could be something as simple as showing the current date or as complex as showing the days orders on an ecommerce site.&nbsp; Take weather.com for example:&nbsp; you input your zip code and it tells you the weather in your area.&nbsp; The content is customized based on your input.</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/28-website-vs-web-application</guid>
      <pubDate>Thu, 09 Sep 2010 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/28-website-vs-web-application</feedburner:origLink></item>
    <item>
      <title>What is custom software development?</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/70EJpNhUNDw/27-what-is-custom-software-development-</link>
      <description>
<![CDATA[Parker Smith Software is a custom software development firm, but what does that really mean?
Well in our business there are 2 classes of software:&nbsp; custom and off the shelf.&nbsp; An off the ...]]>      </description>
      <content:encoded>
<![CDATA[<p>Parker Smith Software is a custom software development firm, but what does that really mean?</p>
<p>Well in our business there are 2 classes of software:&nbsp; custom and off the shelf.&nbsp; An off the shelf software is one that has been pre-made for a general audience and a general purpose, some examples would include:&nbsp;QuickBooks, Microsoft Word, Adobe Reader etc.&nbsp; A custom software is simply one that is created because a viable off the shelf solution doesn't exist, or it doesn't fit the client's needs entirely and can't be modified to do so.</p>
<p>A custom software doesn't have to be a desktop program that is installed on your computer, genreally there are 3 types of software installations: desktop (on your computer), mobile (on your phone) and web based (always accessable online via the internet).&nbsp; Most commonly we work with web based softwares, these range from simple &quot;content management systems&quot; that allow a business to update their website to complex applications that manage the minute by minute operations of an entire company.</p>
<p>In short custom software is business automation by allowing a computer to do certain jobs faster and more effeciently thus allowing people to work on more interesting, productive and creative things.</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/27-what-is-custom-software-development-</guid>
      <pubDate>Tue, 07 Sep 2010 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/27-what-is-custom-software-development-</feedburner:origLink></item>
    <item>
      <title>We're now a virtual office - finally!</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/3XO3ltAL9hc/26-we-re-now-a-virtual-office---finally-</link>
      <description>
<![CDATA[Everyday, people pay for things they don't need.&nbsp; Sometimes those people (okay, us) just shrug and think, &quot;Oh, well.&quot;&nbsp; And other times they stop, look around, and think, &quot;H...]]>      </description>
      <content:encoded>
<![CDATA[<p>Everyday, people pay for things they don't need.&nbsp; Sometimes those people (okay, us) just shrug and think, &quot;Oh, well.&quot;&nbsp; And other times they stop, look around, and think, &quot;Hey! That's dumb!&quot;</p>
<p>We've been using a loft downtown as our physical office for a while now, but the thing is, we don't actually need it.&nbsp; Sure, a bricks and mortar structure is necessary for a lot of businesses.&nbsp; But we do almost all of our work, project management and administration online.&nbsp; We&rsquo;ve been working virtually, in a sense, for a long time.&nbsp;</p>
<p>One of the primary reasons for that is our staff.&nbsp; Most of our employees are located in other cities across the country.&nbsp; Having the flexibility of a &quot;virtual office&quot; has allowed Parker Smith to move beyond the limits of a physical location and to expand our hiring choices.&nbsp; Sometimes you meet people who would make model employees, but they live hundreds of miles away and have no desire to move.&nbsp; For us, that's okay.&nbsp; When we hire someone, talent and skills are key, not location.</p>
<p>Our virtual business style also increases the productivity of our staff because time is saved from zero commuting.&nbsp; And our employees are happy working at home, not having to sit in traffic or dress up.</p>
<p>We utilize the many wonders of modern technology to conduct our business virtually - video chatting, instant messaging, you name it.&nbsp; We may not sit right next to them, but we are in constant contact with all of our employees.</p>
<p>When we acquired the loft downtown, we thought it was necessary because we expected to host client meetings there.&nbsp; But in reality, we nearly always travel to our client's place of business.&nbsp; It's easier for them, and it allows us to fully understand their company culture and operations.</p>
<p>And so, we recently found ourselves looking around our neat yet sparse office, and thought, &quot;Hey! This is dumb!&quot;&nbsp; So we ditched it.</p>]]>      </content:encoded>
      <author>amanda@parkersmithsoftware.com (Amanda Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/26-we-re-now-a-virtual-office---finally-</guid>
      <pubDate>Tue, 18 May 2010 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/26-we-re-now-a-virtual-office---finally-</feedburner:origLink></item>
    <item>
      <title>How-to migrate on-disk images to paperclip</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/mRBad1cnbQ0/25-how-to-migrate-on-disk-images-to-paperclip</link>
      <description>
<![CDATA[There have been more than a few occasions where I had images already on the same disk as a paperclip (rails paperclip plugin) attachment and I wanted to transfer those images as attachments.&nbsp; ...]]>      </description>
      <content:encoded>
<![CDATA[<p>There have been more than a few occasions where I had images already on the same disk as a paperclip (rails paperclip plugin) attachment and I wanted to transfer those images as attachments.&nbsp; Here is how I do it:</p>
<p>&nbsp;</p>

<p>
begin 
  loc_banner = "#{RAILS_ROOT}/public/images/#{File.basename(_banner_path)}" 
  file_banner = File.new(loc_banner) 
  temp_banner = Tempfile.new("#{Digest::SHA1.hexdigest(Time.now.to_s)}.jpg") 

  while !file_banner.eof? 
    temp_banner.write file_banner.read 
  end 

  self.banner = temp_banner #set the paperclip attachment here 

rescue 
  puts "Couldn't set image #{self.id}" 
end
</code>

<p>Note that thiscode would need to require &quot;digest/sha1&quot;</p>
]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/25-how-to-migrate-on-disk-images-to-paperclip</guid>
      <pubDate>Mon, 17 May 2010 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/25-how-to-migrate-on-disk-images-to-paperclip</feedburner:origLink></item>
    <item>
      <title>TextMate bundle shortcuts </title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/OYjHtimJ32M/23-textmate-bundle-shortcuts-</link>
      <description>
<![CDATA[When coding Ruby On Rails projects we use the OS X program TextMate.  Its one of the best development environments in our opinion.  The thing that makes it really awesome is it's ability to have cu...]]>      </description>
      <content:encoded>
<![CDATA[<p>When coding Ruby On Rails projects we use the OS X program TextMate.  Its one of the best development environments in our opinion.  The thing that makes it really awesome is it's ability to have custom "bundles" added in.  A bundle allows you to add in new shortcut keys which are specific to a particular filetype and specify code shippets that get pasted into your file when you hit hit that shortcut.  Even better is that you can have it place your cursor at a particular point in the snippet and you can hit tab to move to other locations.</p>  

<p>For example.  We're really picky about having clean HTML, so we always put a comment at the closing tag.  In any HTML, ERB, or other template file hitting CMD + SHIFT + <  pastes the following code:</p>

<p>
<div class="">

</div><!-- end . -->
</code>

<p>When this code is pasted in the "div" is automatically highlited, if you wanted a div just hit tab and it will highlight the "class".  If not just type what you wanted, maybe a "span" tag.  When you change the tag type that closing tag will automatically get changed as you type.  When you have hit tab to move to the "class" if you didn't want a class attribute just type what you wanted, maybe an "id".  Hitting tab a 3rd time will put the cursor inside the quotes where you can name your attribute.  Thus with 4 keystrokes (minus typing 'fubar') we can get this:</p>

<p>
<div class="fubar">

</div><!-- end .fubar -->
</code>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/23-textmate-bundle-shortcuts-</guid>
      <pubDate>Sat, 25 Jul 2009 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/23-textmate-bundle-shortcuts-</feedburner:origLink></item>
    <item>
      <title>background process manager script</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/0VGWS9tXvU8/22-background-process-manager-script</link>
      <description>
<![CDATA[We're working on a project right now that uses starling + workling for sending email in the background as well as daemons to send out send out periodic emails (also in the background).  So in our d...]]>      </description>
      <content:encoded>
<![CDATA[<p>We're working on a project right now that uses starling + workling for sending email in the background as well as daemons to send out send out periodic emails (also in the background).  So in our development environment it quickly became a pain to start starling, then start the daemon every time someone started working on the project, then killing processes when you're done.  We kept hitting errors in the code, only to realize that it was because the background task mangers weren't running.  So we came up with this little script to make it easy, just:</p>
<p>script/background start development</p>
<p>and then when you're all done.</p>
<p>script/background stop</p>
<p>Here's the code, just put it in script/background of your rails project:</p>
<p>&nbsp;</p>
<p>
<p>



require 'optparse' 
require 'rdoc/usage'
require 'ostruct'
require 'date'


class App
  VERSION = '0.0.1'
  
  attr_reader :options

  def initialize(arguments, stdin)
    @arguments = arguments
    @stdin = stdin
    
    # Set defaults
    @options = OpenStruct.new
    @options.verbose = false
    @options.quiet = false
    @local_exists = false
    @remote_exists = false

  end #end initialize


  # Parse options, check arguments, then process the command
  def run
        
    if parsed_options? && arguments_valid? 
      
      puts "Start at #{DateTime.now}\n\n" if @options.verbose
      
      output_options if @options.verbose # [Optional]
            
      process_arguments            
      process_command
      
      puts "\nFinished at #{DateTime.now}" if @options.verbose
      
    else
      output_usage
    end
      
  end
  
  protected
  
    def parsed_options?
      
      # Specify options
      opts = OptionParser.new 
      opts.on('-v', '--version')    { output_version ; exit 0 }
      opts.on('-h', '--help')       { output_help }
      opts.on('-V', '--verbose')    { @options.verbose = true }  
      opts.on('-q', '--quiet')      { @options.quiet = true }
            
      opts.parse!(@arguments) rescue return false
      
      process_options
      true      
    end

    # Performs post-parse processing on options
    def process_options
      @options.verbose = false if @options.quiet
    end
    
    def output_options
      puts "Options:\n"
      
      @options.marshal_dump.each do |name, val|        
        puts "  #{name} = #{val}"
      end
    end

    # True if required arguments were provided
    def arguments_valid?
    
      if @arguments.length >= 1
        if @arguments[0] == "stop"
          true
        else
          if @arguments[1] == "development" || @arguments[1] == "test" || @arguments[1] == "production"
            true
          end
        end
      end
    
    end
    
    # Setup the arguments
    def process_arguments
      @start = @arguments[0] == "start" ? true : false
      @stop = @arguments[0] == "stop" ? true : false
      @env = @arguments.length > 1 ? @arguments[1] : nil
    end
    
    def output_help
      output_version
      RDoc::usage() #exits app
    end
    
    def output_usage
      RDoc::usage('usage') # gets usage from comments above
    end
    
    def output_version
      puts "#{File.basename(__FILE__)} version #{VERSION}"
    end
    
    def process_command

      if @start
        
        starling_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && starling -d -P tmp/pids/starling.pid -q log/
        end_command

        workling_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && RAILE_ENV=#{@env} script/workling_client start
        end_command
        
        daemon_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && RAILS_ENV=#{@env} lib/daemons/mailer_ctl start
        end_command

        starling_command.gsub!(/\s+/, " ")
        workling_command.gsub!(/\s+/, " ")
        daemon_command.gsub!(/\s+/, " ")

        puts "\nStarting Starling..." unless @options.quiet
        s_success = Kernel.system(starling_command)
        if !s_success && $?.exitstatus != 0
          raise "!!! Starling startup failed !!!"
        else
          puts "Starling started successfully.\n\n" unless @options.quiet
        end
        
        sleep 1
        
        puts "Starting Workling..." unless @options.quiet
        w_success = Kernel.system(workling_command)
        if !w_success && $?.exitstatus != 0
          raise "!!! Workling startup failed !!!"
        else
          puts "Workling started successfully.\n\n" unless @options.quiet
        end
        

        
      elsif @stop
        
        starling_command = <<-end_command
          kill `ps -aef | grep starling | grep -v grep | awk '{print $2}'`
        end_command

        workling_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && RAILE_ENV=#{@env} script/workling_client stop
        end_command
        
        daemon_command = <<-end_command
          cd #{File.dirname(__FILE__) + '/../'} && lib/daemons/mailer_ctl stop
        end_command

        starling_command.gsub!(/\s+/, " ")
        workling_command.gsub!(/\s+/, " ")
        daemon_command.gsub!(/\s+/, " ")
        
        puts "\nStopping Workling..." unless @options.quiet
        w_success = Kernel.system(workling_command)
        if !w_success && $?.exitstatus != 0
          raise "!!! Workling shutdown failed !!!"
        else
          puts "Workling stopped successfully.\n\n" unless @options.quiet
        end
        
        sleep 1

        puts "Stopping Starling..." unless @options.quiet
        s_success = Kernel.system(starling_command)
        if !s_success && $?.exitstatus != 0
          raise "!!! Starling shutdown failed !!!"
        else
          puts "Starling stopped successfully.\n\n" unless @options.quiet
        end
        

  
      end

    end #end process_command


    
end #end App Class


# Create and run the application
app = App.new(ARGV, STDIN)
app.run

</code>
</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/22-background-process-manager-script</guid>
      <pubDate>Thu, 28 May 2009 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/22-background-process-manager-script</feedburner:origLink></item>
    <item>
      <title>auto_complete in rails 2</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/hJxt0EWZIVs/20-auto_complete-in-rails-2</link>
      <description>
<![CDATA[In rails 2 the auto_complete functionality has been moved into a plugin, so to use it you will need to first install the plugin with:


script/plugin install auto_complete


Now you can use t...]]>      </description>
      <content:encoded>
<![CDATA[<p>In rails 2 the auto_complete functionality has been moved into a plugin, so to use it you will need to first install the plugin with:</p>

<p>
script/plugin install auto_complete
</code>

<p>Now you can use the same auto complete functionality you are used to by adding the auto_complete_for declaration to your controller.  One last gotcha is the route, you will have to add it to your routes.rb.  One thing that may help if you have quite a few auto complete fields is to add a wild card route like so:</p>

<p>
map.auto_complete ':controller/:action', 
     :requirements => { :action => /auto_complete_for_\S+/ },
     :conditions => { :method => :get }
</code>
]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/20-auto_complete-in-rails-2</guid>
      <pubDate>Mon, 15 Dec 2008 00:00:00 -0500</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/20-auto_complete-in-rails-2</feedburner:origLink></item>
    <item>
      <title>A script to make adding new GIT repositories easier</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/huL3dC9Z6nM/19-a-script-to-make-adding-new-git-repositories-easier</link>
      <description>
<![CDATA[My friend Jesse and I were trying to figure out a way to make the process of working with new GIT repositories easier.  We wanted to create a new GIT repository locally, creating a new remote repos...]]>      </description>
      <content:encoded>
<![CDATA[<p>My friend Jesse and I were trying to figure out a way to make the process of working with new GIT repositories easier.  We wanted to create a new GIT repository locally, creating a new remote repository and adding the remote to the local so that you can push your development changes out for others to collaborate with. This involves a number of commands locally, then logging into your server, creating folders and git repositories there, then adding the remote repository to your local copy.  Here is our current workflow:</p>


<p>
<p> 
#locally 
git init git add . git commit -m &quot;initial import&quot;  

#remote server 
cd /var/git mkdir newproject.git &amp;&amp; cd newproject.git git --bare init  

#locally 
git remote add origin ssh://user@domain.com:35432/var/git/newproject.git 
git push origin master
</code>
</p>

<p>That isn't a ton of work but it is a repetitive task that could be simplified.  We started with  some ideas of shell scripts and I ended up creating a script in Ruby that handles everything.  It is called GNR which represented GIT - New - Repository when we came up with the concept.  The script does all the commands above for you.  Lets look at an example.</p>

<p>
<p> 
#create a new dummy rails project
rails newproj 

gnr newproj ssh://user@domain.com:35432/var/git/newproj.git
</code>
</p>

<p>That's it.  Now we can CD into the newproj directory and start working.  There are a couple assumptions that this script makes though:</p>

<p>
1.  You are using public/private RSA keys to login to your SSH server without passwords<br />
2.  Your user in the remote repo URL string (user@domain.com) has privileges to be able to write to the directory where your repositories are stored (/var/git in this example)</p>

<p>So here is the code:</p>
<p>&nbsp;</p>

<p>
<p>

require 'optparse' 
require 'rdoc/usage'
require 'ostruct'
require 'date'


class App
  VERSION = '0.0.1'
  
  attr_reader :options

  def initialize(arguments, stdin)
    @arguments = arguments
    @stdin = stdin
    
    # Set defaults
    @options = OpenStruct.new
    @options.verbose = false
    @options.quiet = false
    @local_exists = false
    @remote_exists = false

  end #end initialize


  # Parse options, check arguments, then process the command
  def run
        
    if parsed_options? && arguments_valid? 
      
      puts "Start at #{DateTime.now}\n\n" if @options.verbose
      
      output_options if @options.verbose # [Optional]
            
      process_arguments            
      process_command
      
      puts "\nFinished at #{DateTime.now}" if @options.verbose
      
    else
      output_usage
    end
      
  end
  
  protected
  
    def parsed_options?
      
      # Specify options
      opts = OptionParser.new 
      opts.on('-v', '--version')    { output_version ; exit 0 }
      opts.on('-h', '--help')       { output_help }
      opts.on('-V', '--verbose')    { @options.verbose = true }  
      opts.on('-q', '--quiet')      { @options.quiet = true }
            
      opts.parse!(@arguments) rescue return false
      
      process_options
      true      
    end

    # Performs post-parse processing on options
    def process_options
      @options.verbose = false if @options.quiet
    end
    
    def output_options
      puts "Options:\n"
      
      @options.marshal_dump.each do |name, val|        
        puts "  #{name} = #{val}"
      end
    end

    # True if required arguments were provided
    def arguments_valid?
      true if @arguments.length >= 1 
    end
    
    # Setup the arguments
    def process_arguments
      @project_folder = @arguments[0]
      @repo = @arguments[1] ? @arguments[1] : nil
    end
    
    def output_help
      output_version
      RDoc::usage() #exits app
    end
    
    def output_usage
      RDoc::usage('usage') # gets usage from comments above
    end
    
    def output_version
      puts "#{File.basename(__FILE__)} version #{VERSION}"
    end
    
    def process_command
      
      FileUtils.cd(@project_folder, :verbose => @options.verbose) do
        begin
          FileUtils.cd(".git", :verbose => @options.verbose) do 
            @local_exists = true
            puts "Local repository already exists" unless @options.quiet
            config = File.new("config").read
            @remote_exists = true if config =~ /remote "origin"/
          end
        rescue
          %x[git init]
          %x[git add .]
          %x[git commit -m "Created initial local repo"]
          
          #ssh to server and make new repo.git
          if @repo
            
            #get the repo string into usable vars
            user = @repo.gsub("ssh://","").split("@")[0]
            domain = @repo.gsub("ssh://","").split("@")[1].split(":")[0]
            port = @repo.gsub("ssh://", "").split(":")[1].split("/")[0]
            remote_repo = @repo.gsub("ssh://", "").split(":")[1][@repo.gsub("ssh://", "").split(":")[1].index("/"), @repo.gsub("ssh://", "").split(":")[1].length]
            root_folder = remote_repo[0,remote_repo.rindex("/")]
            repo_folder = remote_repo[remote_repo.rindex("/")+1, remote_repo.length]
            repo_string = %(ssh://#{user}@#{domain}:#{port}#{root_folder}/#{repo_folder})
            
            commands = ["cd #{root_folder}", "mkdir #{repo_folder}", "cd #{repo_folder}", "git --bare init"]
            
            #ssh into the server and create the remote repo
            ssh_string = %(ssh -fCT #{user}@#{domain} -p #{port} "#{commands.join(" && ")}")
            Kernel.system "#{ssh_string}"
            
            #add the remote repo to the local repo
            Kernel.system "git remote add origin #{repo_string}"
            
            #push the local to the remote
            %x[git push origin master]
          
          end #end if @repo
        
        end #end rescue
      
      end #end FileUtils.cd
      
    end #end process_command
    
end #end App Class


# Create and run the application
app = App.new(ARGV, STDIN)
app.run


</code>
</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/19-a-script-to-make-adding-new-git-repositories-easier</guid>
      <pubDate>Fri, 07 Nov 2008 00:00:00 -0500</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/19-a-script-to-make-adding-new-git-repositories-easier</feedburner:origLink></item>
    <item>
      <title>Improve your workflow with aliases</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/KJuELbMhjik/18-improve-your-workflow-with-aliases</link>
      <description>
<![CDATA[When working with the command line there are a lot of different commands that you may use, git add, git commit, mysql  etc.  So why not improve your workflow and speed by making an alias or two to ...]]>      </description>
      <content:encoded>
<![CDATA[<p>When working with the command line there are a lot of different commands that you may use, git add, git commit, mysql  etc.  So why not improve your workflow and speed by making an alias or two to do those commands.  This example assumes that you are working on a Unix based operating system and using bash as your shell.  This is the case in our development environment on Mac OS X.  The default shell in OS X is bash, so we'll stick these alias lines in a file names .bash_profile that sits in your home directory.  So for me this is /Users/brian/.bash_profile.  Here are the aliases:</p>

<p>
alias memcached_start='/opt/local/bin/memcached -d -m 64 -u www -l 127.0.0.1 -p 11211'
alias memcached_stop='sudo killall memcached'

#ssh
alias connect='ssh -p 29876 '

#top
alias tu='top -o cpu' #cpu
alias tm='top -o vsize' #memory

#git
alias gb='git branch'
alias gba='git branch -a'
alias gcv='git commit -v'
alias gcm='git commit -m'
alias gd='git diff | mate'
alias gl='git pull'
alias gp='git push'
alias ga='git add'
alias gaa='git add . && echo "git added ."'
alias gpa='echo "running: git push --all" && git push --all'
alias gst='git status'

#textmate
alias et='mate .&'
alias ett='mate app config lib db public test vendor/plugins &'

#ruby
alias att='autotest'

#mysql
alias mysql='/usr/local/bin/mysql/mysql'
alias mysqladmin='/usr/local/bin/mysql/mysqladmin'
alias mysqlstart='sudo /usr/local/bin/mysql/mysqld_safe &'
alias mysqlstop='/usr/local/bin/mysql/mysqladmin -u root -p shutdown'
alias sql='mysql -u root -p'
</code>

<p>After editing the file you can either quit and restart your terminal, or you can run:</p>

<p>
source ~/.bash_profile
</code>

<p>Now you have all these really cool alias commands that make your workflow really fast.  For example, say you have been working on some code and need to add, commit, and push the code to the origin server.  Use the aliases....</p>

<p>
gaa
gcm "added foo bar feature"
gpa
</code>
]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/18-improve-your-workflow-with-aliases</guid>
      <pubDate>Thu, 06 Nov 2008 00:00:00 -0500</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/18-improve-your-workflow-with-aliases</feedburner:origLink></item>
    <item>
      <title>Parker Smith gets office space in Glassworks Building</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/CLnDRSA6Ryk/15-parker-smith-gets-office-space-in-glassworks-building</link>
      <description>
<![CDATA[Parker Smith has moved into a loft in the Glassworks Building in downtown Louisville, at the corner of Market and Ninth Streets.  We're located on the sixth floor, in Suite 603.  We're loving life ...]]>      </description>
      <content:encoded>
<![CDATA[Parker Smith has moved into a loft in the Glassworks Building in downtown Louisville, at the corner of Market and Ninth Streets.  We're located on the sixth floor, in Suite 603.  We're loving life in our giant concrete box -- stop by and see us!]]>      </content:encoded>
      <author>amanda@parkersmithsoftware.com (Amanda Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/15-parker-smith-gets-office-space-in-glassworks-building</guid>
      <pubDate>Wed, 05 Nov 2008 00:00:00 -0500</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/15-parker-smith-gets-office-space-in-glassworks-building</feedburner:origLink></item>
    <item>
      <title>Remote execution of commands via SSH</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/JP45KjtcvME/17-remote-execution-of-commands-via-ssh</link>
      <description>
<![CDATA[Often when we have a long list of commands that we need to run on a remote server we'll use Capistrano to do this.  Especially if the tasks are related to a project and we'll be moving files to the...]]>      </description>
      <content:encoded>
<![CDATA[<p>Often when we have a long list of commands that we need to run on a remote server we'll use Capistrano to do this.  Especially if the tasks are related to a project and we'll be moving files to the server, creating directories, restarting processes etc.  But what if the task to be completed on the remote server isn't that complex, maybe just a couple commands.  In this application Capistrano seems a little overkill, but at the same time we don't want to login and execute the commands manually, there is a better way.  Lets see how...</p>

<p>For this example we'll be running commands for an OpenSSH server, and we have a password-less login enabled through the use of public/private keys.  Enough talk, how do we do it, well we start with the SSH command and some options</p>

<p>
ssh -fCT user@domain.com pwd
</code>

<p>Lets look at the options and what they mean:<br />
-f = Tells SSH to close after the session is established<br />
-C = Tells SSH to use compression<br />
-T = Means that no terminal session will be started</p>

<p>So the above command will login to the remote server via SSH and execute the 'pwd' command and the output will be displayed in the terminal window.  That is cool, but it is a pretty simple example, its not often that we are running 'pwd' remotely, additionally at Parker Smith for security we never run SSH on the default port 22.  To do this we can expand the example a little more using some more SSH options.</p>

<p>
ssh -fCT user@domain.com -p 29746 "mkdir /home/user/test; ps wax >> /home/user/test/processes.txt"
</code>

<p>Now this example is a bit more complex and could be more adaptable to your situation.  We are logging into SSH running on port 29746 and we quote the commands separated by a semicolon.  This particular command will login to the server, make a directory called test in the user's home directory, then list some processes and write them into a text file within that directory.</p>

<p>To take this another step further you could pass a shell script as the last argument instead of a command, and the list of commands in the script will be executed.  This is a little easier than trying to put all the commands in a string.</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/17-remote-execution-of-commands-via-ssh</guid>
      <pubDate>Sun, 02 Nov 2008 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/17-remote-execution-of-commands-via-ssh</feedburner:origLink></item>
    <item>
      <title>Parker Smith to develop fitness training application for Olympic champion</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/W_f_N8WPqMU/16-parker-smith-to-develop-fitness-training-application-for-olympic-champion</link>
      <description>
<![CDATA[We're currently working on a web application for Carl Lewis, a nine-time gold medalist in track and field.  Carl is starting FitForever.com, an online personal training site that encourages lifelon...]]>      </description>
      <content:encoded>
<![CDATA[We're currently working on a web application for Carl Lewis, a nine-time gold medalist in track and field.  Carl is starting FitForever.com, an online personal training site that encourages lifelong fitness.  Features will include workout tracking, food and calorie intake tracking, ways to share weight loss progress with friends, online fitness communities, instructional videos, and a companion iPhone application that logs workouts and dietary intake in real time.  Interactive design agency Visual Scientists is creating the interface, and we are handling the back-end software component.  We have also been working with VS on Carl's personal website, CarlLewis.com.  ]]>      </content:encoded>
      <author>amanda@parkersmithsoftware.com (Amanda Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/16-parker-smith-to-develop-fitness-training-application-for-olympic-champion</guid>
      <pubDate>Mon, 20 Oct 2008 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/16-parker-smith-to-develop-fitness-training-application-for-olympic-champion</feedburner:origLink></item>
    <item>
      <title>Create a simple load balancer with Nginx</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/Xn9o--Actuk/14-create-a-simple-load-balancer-with-nginx</link>
      <description>
<![CDATA[So lets say that you want to make your own simple load balancer, to round robin requests between multiple servers; those servers will be running their own web server software which will be doing a ...]]>      </description>
      <content:encoded>
<![CDATA[<p>So lets say that you want to make your own simple load balancer, to round robin requests between multiple servers; those servers will be running their own web server software which will be doing a reverse proxy to load balance rails requests amongst mongrel, thin, ebb etc.  (if its a rails app). </p>

<p>The requirements are that the main load balancer needs to handle HTTP and HTTPS requests and it should automatically add or remove cluster nodes from the server pool as they become available, or unavailable.  We can accomplish this by using the Nginx webserver. </p>

<p>We setup Nginx as you normally would perhaps using 6 or 7 workers, and you can setup the load balancing in the vhost config file.  Instead of creating server pools of backend mongrels as you may have seen before, just make the items in the pool each point to a different server.  In this example we actually store the IP locations in our /etc/hosts file. </p>

<p>
upstream backend {
  server web1:80;
  server web2:80;
  server web3:80;
  server web4:80;
  server web5:80;
}

upstream secure {
  server web1:443;
  server web2:443;
  server web3:443;
  server web4:443;
  server web5:443;
}



server {

  listen 80;

  server_name www.domain.com domain.com;

  location / {

    # needed to forward user's IP address to rails
    proxy_set_header  X-Real-IP  $remote_addr;

    # needed for HTTPS
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect false;
    proxy_max_temp_file_size 0;

    proxy_pass http://backend;

  } #end location

} #end server



server {

  listen 443;

  ssl on;
  ssl_certificate /etc/ssl/ssl.pem/www.domain.com.pem;
  ssl_certificate_key /etc/ssl/ssl.key/www.domain.com.key;

  server_name www.domain.com domain.com;

  location / {

    # needed to forward user's IP address to rails
    proxy_set_header  X-Real-IP  $remote_addr;

    # needed for HTTPS
    #proxy_set_header X_FORWARDED_PROTO https;

    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect false;
    proxy_max_temp_file_size 0;

    proxy_pass https://secure;

  } #end location


} #end server
</code>

<p>Thats all there is to it, now this box will act as a front end load balancer in front of a number of other servers, adding a server is just 1 entry in each of the pools.</p>

<p class="em">Note, be sure your log levels for Nginx are set to error only, since this Nginx instance will be handling a lot of traffic the logs can fill up really fast.</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/14-create-a-simple-load-balancer-with-nginx</guid>
      <pubDate>Wed, 17 Sep 2008 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/14-create-a-simple-load-balancer-with-nginx</feedburner:origLink></item>
    <item>
      <title>Using GMail to send email from Rails</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/FI9OM3jTcI8/13-using-gmail-to-send-email-from-rails</link>
      <description>
<![CDATA[Sometimes when we are making applications that send email we need to send them from our development machines, I'm not a fan of installing postfix or other MTA (mail transfer agent) software on ever...]]>      </description>
      <content:encoded>
<![CDATA[<p>Sometimes when we are making applications that send email we need to send them from our development machines, I'm not a fan of installing postfix or other MTA (mail transfer agent) software on everyone's computer, and that also adds another level of complexity for cross platform development.  Instead we'd rather have everything all integrated into our rails application so that it just works for development, then leave the setup of postfix or another MTA to the deployment process.  We do this by setting up the rails application to send email through GMail or Google Apps in development mode, and the server MTA in production mode.</p>

<p class="em">One side note, it probably isn't a good idea to send email this way in production mode since your app can stall while the email is being sent, and an MTA will have a mail queue to handle that.</p>

<p>To work with GMail we have to connect to SMTP through SSL, to do this we need to install the 'tlsmail' gem.</p>

<p>
sudo gem install tlsmail
</code>

Next create an initializer in config/initializers:

<p>
# config/initializers/email_config.rb

if ENV['RAILS_ENV'] == "production"
  
  ActionMailer::Base.delivery_method = :smtp
  ActionMailer::Base.smtp_settings = {
    :address => '127.0.0.1',
    :port => 25,
    :domain => 'localhost'
  }

else

  #setup tlsmail so we can send email through SSLed SMTP
  require 'tlsmail'
  Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)

  ActionMailer::Base.delivery_method = :smtp
  ActionMailer::Base.smtp_settings = {
    :address => 'smtp.gmail.com',
    :port => 587,
    :domain => 'yourdomain.com',
    :authentication => :plain,
    :user_name => 'maileraccount@yourdomain.com',
    :password => 'yourpassword'
  }
  
end #end if
</code>

<p>If you are using a Google Apps account then just replace the domain and username info with your own, if you are just using a gmail account the domain is gmail.com and the username is just your GMail id without the @gmail.com.  </p>

<p class="em">One thing to note, Google has limits on outgoing emails of about 100 per day per account to prevent people from using their service to send out spam.</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/13-using-gmail-to-send-email-from-rails</guid>
      <pubDate>Mon, 18 Aug 2008 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/13-using-gmail-to-send-email-from-rails</feedburner:origLink></item>
    <item>
      <title>Respond to server prompts in Capistrano</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/taObNEhZZ8E/12-respond-to-server-prompts-in-capistrano</link>
      <description>
<![CDATA[At Parker Smith we try to use Capistrano as much as possible to do routine tasks for us, sometimes it is something where the server requires some sort of input during the process, like creating a u...]]>      </description>
      <content:encoded>
<![CDATA[<p>At Parker Smith we try to use Capistrano as much as possible to do routine tasks for us, sometimes it is something where the server requires some sort of input during the process, like creating a user, then supplying and confirming a password.  With the Capistrano defaults you'll see the prompt, the script will halt, and you won't be able to get your response to the server.  Here is how you fix that:</p>

<p>
# in deploy.rb
default_run_options[:pty] = true
</code>

<p>Setting the pty run option is what tells Capistrano to allow you to give response input to the script from the terminal, the next step is all in how you tell Capistrano to execute the command.  Lets say that our task is to create a new user on the server and supply a password.</p>

<p>
# deploy.rb

set :new_user, "myuser"
set :new_user_pw, "secret"

desc "Setup a new user and supply the password"
task :setup_user do
  run "useradd  -m -d /home/#{new_user} -s /bin/bash #{new_user}"

  run "passwd #{new_user}" do |ch, stream, out|
    ch.send_data "#{new_user_pw}"+"\n" if out =~ /Enter new UNIX password:/
    ch.send_data "#{new_user_pw}"+"\n" if out =~ /Retype new UNIX password:/
  end

end
</code>

<p>Lets take a look at the code above, first we set variables for the new username and their password, this is what will get sent to the server in the command to create a new user. Next is the setup_user task, in this particular example we are executing this task as root, perhaps this is the first time you have setup any users on the new machine, if not you could just change the "run" statements to "sudo". </p>

<p>The second command in the task runs the 'passwd' command, grabs the output, and sends information back.  The 'out' variable is the output from the server prompt, we use a REGEX pattern to match what the prompt is, so we can make a decision on what to send back.</p>

<p>Thats it, now to setup your new user just run:</p>

<p>
cap setup_user
</code>

<p class="em">If you want to run the command with a different user or port, just run your cap command like this:</p>

<p>
cap setup_user -s user=root -s port=22
</code>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/12-respond-to-server-prompts-in-capistrano</guid>
      <pubDate>Thu, 10 Jul 2008 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/12-respond-to-server-prompts-in-capistrano</feedburner:origLink></item>
    <item>
      <title>Capistrano with a SVN repon on the deploy_to server</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/h4-nhHC5nVE/11-capistrano-with-a-svn-repon-on-the-deploy_to-server</link>
      <description>
<![CDATA[Sometimes when you deploy with Capistrano you have just one server that acts in many roles (web, app, database all in one). When I have a client that has a single server for a single app I'll often...]]>      </description>
      <content:encoded>
<![CDATA[<p>Sometimes when you deploy with Capistrano you have just one server that acts in many roles (web, app, database all in one). When I have a client that has a single server for a single app I'll often setup an SVN repo to be accessed via svn+ssh. This causes a little bit of a hickup when you try to deploy with Capistrano because you need to tell the server to checkout the code from itself, but that isn't the same access pattern you need when you are committing things to the svn as a developer. Of course you could deploy_via :copy but that takes a bit longer, an easier route is to have one SVN access pattern for the server to checkout the code, and a different one for yourself as a remote machine. Here is how:</p>

<p>Here is an example deploy.rb file.</p>

<p>
require 'mongrel_cluster/recipes'

# setup vars used later in the script
set :application, "yourdomain_com"
set :user, "brian"
set :runner, user
set :main_server, "www.yourdomain.com"

# source code repository
set :local_repository,  "svn+urdomainssh://www.yourdomain.com/repository/#{application}/trunk"
set :repository, "file:////repository/yourdomain_com/trunk"

# ssh port is 29361
set :port, 29361

# set the location for the app on the server
set :deploy_to, "/var/www/apps/#{application}"

set :deploy_via, :checkout

# setup servers
set :domain, main_server
role :app, main_server
role :web, main_server
role :db,  main_server, :primary => true

# post deploy tasks
desc "Link in the production symlinks"
task :after_update_code do

  # link the database.yml file
  run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
  
end #end after_update_code

after "deploy", "deploy:cleanup"
</code>

<p>Notice the directives :local_repository and :repository, the first tells Capistrano how to access the source code repository from your local machine (the one you are deploying code from). The second tells it how to access the repository from the server. We use a local file checkout on the server since we don't want to have to mess with private keys, and self referential connections on the server.</p>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/11-capistrano-with-a-svn-repon-on-the-deploy_to-server</guid>
      <pubDate>Mon, 30 Jun 2008 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/11-capistrano-with-a-svn-repon-on-the-deploy_to-server</feedburner:origLink></item>
    <item>
      <title>resetting the auto_increment counter in MySQL</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/gl6WOjePjJ8/10-resetting-the-auto_increment-counter-in-mysql</link>
      <description>
<![CDATA[Have you ever had a table where you wanted to drop all the information and reset the id field? Say you have the auto_increment value at 1024 and you want to drop all the data and make all new rows ...]]>      </description>
      <content:encoded>
<![CDATA[<p>Have you ever had a table where you wanted to drop all the information and reset the id field? Say you have the auto_increment value at 1024 and you want to drop all the data and make all new rows start from 1. Or maybe you have the auto_increment value at 1024 and you want to jump it to have all new rows start from 10024. Here is how:</p>

<p>
ALTER TABLE {table_name} AUTO_INCREMENT = {new_value};
</code>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/10-resetting-the-auto_increment-counter-in-mysql</guid>
      <pubDate>Wed, 28 May 2008 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/10-resetting-the-auto_increment-counter-in-mysql</feedburner:origLink></item>
    <item>
      <title>max_allowed_packet MySQL error explained</title>
      <link>http://feedproxy.google.com/~r/parkersmith/~3/5dSt14Xq-Cc/9-max_allowed_packet-mysql-error-explained</link>
      <description>
<![CDATA[I was doing some work where I needed to run some heavy queries on a database using the production data. Naturally I made a backup of the database and the plan was to restore it to my local MySQL in...]]>      </description>
      <content:encoded>
<![CDATA[<p>I was doing some work where I needed to run some heavy queries on a database using the production data. Naturally I made a backup of the database and the plan was to restore it to my local MySQL instance on my development box and then run my tests. I hit a couple snags, and in an effort to document everything that I run into that requires some gumshoeing here is how I fixed it.</p>

<p>I read a bunch of people saying you could use –max_allowed_packet=100M in the command line but I had no luck with this. I also found some people who said you could edit my.cnf to put the setting there but the location and existence of this file appears to be different per the platform and installation method for MySQL. The end result is to update the setting directly at the mysql prompt. So:</p>

<p>
mysql> SET GLOBAL max_allowed_packet = 16 * 1024 * 1024;
</code>]]>      </content:encoded>
      <author>brian@artifexsoftware.com (Brian Webb)</author>
      <guid isPermaLink="false">http://www.parkersmithsoftware.com/blog/post/9-max_allowed_packet-mysql-error-explained</guid>
      <pubDate>Thu, 15 May 2008 00:00:00 -0400</pubDate>
    <feedburner:origLink>http://www.parkersmithsoftware.com/blog/post/9-max_allowed_packet-mysql-error-explained</feedburner:origLink></item>
  </channel>
</rss>

