<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Net Perspective's Blog</title>
	
	<link>http://blog.net-perspective.com</link>
	<description>Check out the latest monologues and ramblings for the great people at Net Perspective (http://www.net-perspective.com/)</description>
	<pubDate>Mon, 29 Sep 2008 14:00:50 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.3</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/net-perspective" /><feedburner:info uri="net-perspective" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>This Thing Called Scroll Follow</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/6kXV_7r9NrQ/</link>
		<comments>http://blog.net-perspective.com/2008/09/29/this-thing-called-scroll-follow/#comments</comments>
		<pubDate>Mon, 29 Sep 2008 14:00:50 +0000</pubDate>
		<dc:creator>R.A.</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[jquery]]></category>

		<category><![CDATA[open source]]></category>

		<category><![CDATA[scroll follow]]></category>

		<category><![CDATA[the kitchen]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=151</guid>
		<description><![CDATA[Initially it was developed to solve a problem for a client. I took the opportunity to refine what I knew about writing plugins for jQuery and made it into something we could release into the wild.]]></description>
			<content:encoded><![CDATA[<p class="lead">Initially it was developed to solve a problem for a client. I took the opportunity to refine what I knew about writing plugins for <a href="http://jquery.com/">jQuery</a> and made it into something we could release into the wild.</p>
<p>It is probably a very familiar scenario for many who dabble in the open source realm, but still, when you start helping other developers solve other problems for other clients a <em>thrill</em> is involved. This is, in essence, the spirit behind <a href="http://kitchen.net-perspective.com/">The Kitchen</a>.</p>
<h3>Catching Up</h3>
<p>For the uninitiated, jQuery is an open source javascript library that makes selecting and manipulating objects on the page dead easy, especially if you are used to CSS selector syntax. <a href="http://kitchen.net-perspective.com/open-source/scroll-follow/">Scroll Follow</a> is a plugin for this library that enables a DOM object to follow the page as the user scrolls. </p>
<p>We first released this plugin back in May. With the launch of The Kitchen I've been able to open a dialog with several of our Scroll Follow users expressing interest in moving the script on to bigger and better places and we're thrilled at this <em>development</em> (pun intended).</p>
<p>I was skeptical at first. It's not the kind of design solution I would often use. That's why there is a "kill switch" parameter. Hopefully though, by improving the script and using it judiciously, we can add value for users. </p>
<h3>Coming Soon</h3>
<p>We will soon be releasing version 0.3 of Scroll Follow. In this release I've added a user-requested parameter. Before, the animation was always relative to the top of the user's viewable area, but no longer! You will now be able to key off of the bottom of the window as well as the top.</p>
<p>I have also improved the logic in the script to try to keep the CSS fiddling to a minimum. We want Scroll Follow to work straight out of the box. . . or zip file as it were. To that end we are issuing a call for help! We are looking for a few good, or at least bored, individuals to help us test the current release candidate so we can squash any remaining bugs.</p>
<p>This is not a daunting task! What we need more than anything are the test cases we haven't thought of. It seems the simple things are what cause breakages most. We're sure you can do simple and we're hoping you can do breakage. Are you up for it?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/09/29/this-thing-called-scroll-follow/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/09/29/this-thing-called-scroll-follow/</feedburner:origLink></item>
		<item>
		<title>Being Perfect</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/jKVmcY14mCA/</link>
		<comments>http://blog.net-perspective.com/2008/09/19/being-perfect/#comments</comments>
		<pubDate>Fri, 19 Sep 2008 17:00:42 +0000</pubDate>
		<dc:creator>R.A.</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[process]]></category>

		<category><![CDATA[theory]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=108</guid>
		<description><![CDATA[The saying goes, "Nobody's perfect." Too often, this idea that perfection cannot be obtained is used as an excuse for mediocrity. In response, I ask you to consider a very recent example of perfection.]]></description>
			<content:encoded><![CDATA[<p class="lead">The saying goes, "Nobody's perfect." Too often, this idea that perfection cannot be obtained is used as an excuse for mediocrity. In response, I ask you to consider a very recent example of perfection.</p>
<p><span id="more-108"></span></p>
<p><a href="http://en.wikipedia.org/wiki/Michael_Phelps">Michael Phelps</a> is a phenom, an athlete to whom few comparisons can be made. And, at the recent Beijing Olympics, Phelps went a perfect eight-for-eight in his swimming events. Eight races. Eight gold medals. Perfect. Well, sort of.</p>
<h3>Constraint</h3>
<p>Michael Phelps cannot hit a major league fastball. He can't hang on the track with Usain Bolt or tap out Anderson Silva. Michael Phelps is not the world's strongest man and he cannot leap tall buildings in a single bound. I bet he can't even put together a website. Irrelevant. </p>
<p>We don't care about these caveats because no one has ever suggested that he be anything other than a swimmer. Phelps stuck to the pool. He might have chosen other paths and become a good swimmer and a decent professional cheese grater, but then he wouldn't be selling mobile devices on national TV. He'd be grating cheese. We wouldn't be talking about him.</p>
<p>To be perfect you have to pick something to be perfect <em>at</em>. You must have constraint. </p>
<p>This is difficult for two reasons:</p>
<ol>
<li>You want to do a lot. You want to make websites <em>and</em> multi-function dry-erase boards. You want to be a rancher and drive an Aston Martin. You want to be a star and have a private life. It's not a problem to have multifaceted interests but honestly, perfection takes an extreme level of commitment. If it didn't, I'd have more examples to use.</li>
<li>You don't always know at the start what you will be good at or even enjoy doing. This is an important point. Few people have the constitution to put perfection-level effort into something they don't derive some sort of pleasure from.</li>
</ol>
<h3>Effort</h3>
<p>Effort is easy &hellip; to explain. Effort is what you give. It is what you sacrifice towards whatever perfection you are chasing. Phelps gave most of his life. He gives so much in training that he eats a 14,000 calorie a day diet and is still skinny. He gave most of his Olympic experience; for the first week, he did almost nothing but eat, sleep, swim, and interview.</p>
<p>Effort is hard to maintain for any number of reasons: distraction, boredom, disaster, monetary incentive. Anything that diverts focus is an enemy to perfection and since achievement takes so <em>much</em> effort you're going to face many enemies along the way. </p>
<h3>Luck</h3>
<p>Luck is the polar opposite of effort. Luck is effort's evil stepbrother or fairy godmother depending on what side of it you are on. Luck is what you get for free whether you want it or not.</p>
<p>Michael Phelps got the anatomically perfect swimmer's body. A too-big torso and too-short legs. Over-sized hands and feet and widely articulating shoulder and ankle joints. I'm not a swimming expert, but they say if you were going to <em>build</em> a swimmer this is what you would ask for. Yes, his level of effort is extraordinary, but his natural advantages put him over the top.</p>
<p>Of course, luck is often a matter of perspective. If Phelps had decided to pursue a career as a professional curler his physical proportions would be of little help to him. If you have been paying attention, you realize that we just made our way back to constraint which leads me to this overly simple conclusion: <br /><strong>Intelligent Constraint = Managed Luck</strong>.</p>
<h3>Definition</h3>
<p>The final yellow brick on our road to perfection is the most ethereal. You might say it's a cop-out or you might say it's intrinsic to our discussion. <em>I'm</em> saying it's going to come up. </p>
<p>I don't know the man, but I suspect he doesn't consider himself perfect. I doubt he thinks his Olympic performance was perfect. In fact, he looked disgusted after winning the 200 meter butterfly during which his goggles filled up with water. He said afterward (paraphrasing), "I think I can go faster." To the rest of the world, however, his Olympics were perfect and that is because the rest of us defined perfection differently.</p>
<p>Definition is the goal we are striving for. It is the metric we are going to test our accomplishments against and if you're doing this thing right you'll never achieve your own definition. That doesn't matter really. Putting all that effort into a properly constrained goal means you <em>can</em> achieve perfection in the eyes of others, if you're lucky.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/09/19/being-perfect/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/09/19/being-perfect/</feedburner:origLink></item>
		<item>
		<title>ImagePlane and some simple OOP designs</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/hlO8d7VTbT4/</link>
		<comments>http://blog.net-perspective.com/2008/09/13/imageplane-and-some-simple-oop-designs/#comments</comments>
		<pubDate>Sun, 14 Sep 2008 02:41:32 +0000</pubDate>
		<dc:creator>Daniel Cousineau</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[oop]]></category>

		<category><![CDATA[php]]></category>

		<category><![CDATA[software design]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=132</guid>
		<description><![CDATA[<p class="lead">At <a href="http://www.net-perspective.com/">Net Perspective</a> we created an image editor in flash that we just released for sale called <a href="http://kitchen.net-perspective.com/commercial/image-plane">Image Plane</a>. While Image Plane has already been <a href="http://blog.net-perspective.com/2008/09/10/image-plane-as-easy-as/">creatively introduced</a> and <a href="http://kitchen.net-perspective.com/docs/image-plane/developer/">documented quite thoroughly</a>, I wanted to go over the thought process in designing a&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p class="lead">At <a href="http://www.net-perspective.com/">Net Perspective</a> we created an image editor in flash that we just released for sale called <a href="http://kitchen.net-perspective.com/commercial/image-plane">Image Plane</a>. While Image Plane has already been <a href="http://blog.net-perspective.com/2008/09/10/image-plane-as-easy-as/">creatively introduced</a> and <a href="http://kitchen.net-perspective.com/docs/image-plane/developer/">documented quite thoroughly</a>, I wanted to go over the thought process in designing a reusable set of classes (in this case to assist Image Plane in saving changes).</p>
<p>Currently Image Plane posts saved data to URL via the HTTP POST method. Currently Image Plane posts the entire Base64 encoded image (after transformations), but when designing the example class I had to account for the fact that I might have to someday support just a list of transformations (for the server to duplicate rather than receiving the entire image again). I also would have to support more than 1 output engine (despite the fact that I myself would just be using GD).</p>
<p>In designing my interface I like to make a quick list of operations and objects I will be expected to perform (no, this isn't a waterfall document, the list can be broad but I need a general idea of where I'm going):</p>
<ol>
<li>Set a filename (and by proximity, output directory and type)</li>
<li>Select an output engine (either for performance reasons or simply support)</li>
<li>Constrain image sizes</li>
<li>Set certain image options (JPEG quality, possibly PNG transparency)</li>
</ol>
<p>Now since I know I needed to support multiple output engines, I'm guaranteed to use the <a href="http://en.wikipedia.org/wiki/Adapter_pattern">Adapter pattern</a>. So now we have to split up our tasks among two classes.</p>
<p>Since our Adapter classes will each be very different internally (since they have to emulate and mimic features with different libraries) we'll want to keep them as small and clean as possible. Stepping through the list above we can see that 3 and 4 are obviously a best fit for our Adapter class since they deal directly with the actual image processing. All 2 really happens to be is a <code>setOutputEngine(Adapter_Interface $engine)</code> type method, however you can make it fancier by accepting a string for the engine and finding and instantiating the engine manually, but that's implementation side. Item 1 could be construed as belonging with the image processing but in reality it does not. Setting the output location and type is universal to all libraries, infact it really has nothing to do with image processing.</p>
<p>So we have a nice delegation of tasks to our objects we can start building. First things first, after creating our main shell class we create an interface (since things are so wildly different amongst image processing engines there's not much we can replicate so an interface will work better here as opposed to inheriting an abstract class) for our Adapter class.</p>
<p>The adapter class is going to need to do a few things. Specifically its going to need to load from a string (base64 encoded), set a few options (preserveTransparency and setOutQuality, for jpegs), and save the image data.</p>
<pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">interface</span> ImagePlane_Output_Interface
<span style="color: #66cc66;">&#123;</span>
	<span style="color: #808080; font-style: italic;">/**
	 * @param string $data base64 encoded image
	 * @return ImagePlane_Output_GD fluent interface
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> loadFromString<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$image</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * @param bool $bool
	 * @return ImagePlane_Output_GD fluent interface
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> preserveTransparency<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$bool</span> = <span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Only really used for JPEG
	 *
	 * @param int $quality
	 * @return ImagePlane_Output_GD fluent interface
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setOutQuality<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$quality</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * @param string $outFile output location
	 * @param string $type Image type
	 * @return bool
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> save<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$outFile</span>, <span style="color: #0000ff;">$type</span> = ImagePlane::<span style="color: #006600;">TYPE_JPEG</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
<p>In our primary class we are probably best splitting up the outfile into 3 separate segments. We should force good filenames by making the user put in the output directory, output name, THEN output type. This way we can easily fix our filenames, check directory problems, and enforce output type (and proper extensions) without having to hack through <code>pathinfo</code> results only to find the user specified some weird extension for a type that we didn't account for. Plus this leaves us open to in the future specifying multiple output files without having to include directories on all them, or specifying multiple output types again without having to retype the entire filename.</p>
<pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> ImagePlane
<span style="color: #66cc66;">&#123;</span>
	<span style="color: #808080; font-style: italic;">/**
	 * ImagePlane is passing in final transformed image via base64 POST
	 */</span>
	const INPUT_POST = <span style="color: #ff0000;">'post'</span>;
	<span style="color: #808080; font-style: italic;">/**
	 * CURRENTLY NOT IMPLEMENTED BY IMAGEPLANE
	 */</span>
	const INPUT_TRANSFORMATIONS = <span style="color: #ff0000;">'transformations'</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">//Image Types</span>
	const TYPE_JPEG = <span style="color: #ff0000;">'jpg'</span>;
	const TYPE_PNG = <span style="color: #ff0000;">'png'</span>;
	const TYPE_GIF = <span style="color: #ff0000;">'gif'</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Output engine
	 *
	 * @var ImagePlane_Output_Interface
	 */</span>
	protected <span style="color: #0000ff;">$outputEngine</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Output directory
	 *
	 * @var string
	 */</span>
	protected <span style="color: #0000ff;">$outDirectory</span> = <span style="color: #000000; font-weight: bold;">null</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Output name (without extension)
	 *
	 * @var string
	 */</span>
	protected <span style="color: #0000ff;">$outName</span> = <span style="color: #000000; font-weight: bold;">null</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Output type
	 *
	 * @var string
	 */</span>
	protected <span style="color: #0000ff;">$outType</span> = <span style="color: #000000; font-weight: bold;">null</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Create new ImagePlane instance using a certain output engine
	 *
	 * @param ImagePlane_Output_Interface $outputEngine
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #66cc66;">&#40;</span>ImagePlane_Output_Interface <span style="color: #0000ff;">$outputEngine</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">setOutputEngine</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$outputEngine</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Set the image output directory
	 *
	 * @param string $directory
	 * @return ImagePlane fluent interface
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setOutDirectory<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$directory</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #b1b100;">if</span><span style="color: #66cc66;">&#40;</span> !<a href="http://www.php.net/is_writable"><span style="color: #000066;">is_writable</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$directory</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span>
		<span style="color: #66cc66;">&#123;</span>
			throw <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Output directory is not writeable&quot;</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #66cc66;">&#125;</span>
&nbsp;
		<span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">outDirectory</span> = <span style="color: #0000ff;">$directory</span>;
&nbsp;
		<span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$this</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Get the image output directory
	 *
	 * @return string
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getOutDirectory<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #b1b100;">return</span> <a href="http://www.php.net/rtrim"><span style="color: #000066;">rtrim</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">outDirectory</span>, <span style="color: #ff0000;">'<span style="color: #000099; font-weight: bold;">\\</span>/'</span><span style="color: #66cc66;">&#41;</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Output filename (without extension)
	 *
	 * The filename is automatically stripped of any characters other than 'A-Z',
	 * '0-9', '_', and '-', and are replaced with a dash.
	 *
	 * @param string $name
	 * @return ImagePlane fluent interface
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setOutName<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$name</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">outName</span> = <a href="http://www.php.net/preg_replace"><span style="color: #000066;">preg_replace</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;/[^[:alnum:]_-]+/&quot;</span>, <span style="color: #ff0000;">'-'</span>, <span style="color: #0000ff;">$name</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
		<span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$this</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Get the output filename (without extension)
	 *
	 * @return string
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getOutName<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">outName</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Set output type.
	 *
	 * Valid options are:
	 *  - ImagePlane::TYPE_JPEG
	 *  - ImagePlane::TYPE_PNG
	 *  - ImagePlane::TYPE_GIF
	 *
	 * @param string $type
	 * @return ImagePlane fluent interface
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setOutType<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$type</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #b1b100;">if</span><span style="color: #66cc66;">&#40;</span> !<a href="http://www.php.net/in_array"><span style="color: #000066;">in_array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$type</span>, <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span>self::<span style="color: #006600;">TYPE_PNG</span>, self::<span style="color: #006600;">TYPE_JPEG</span>, self::<span style="color: #006600;">TYPE_GIF</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span>
			throw <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Invalid Type&quot;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
		<span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">outType</span> = <span style="color: #0000ff;">$type</span>;
&nbsp;
		<span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$this</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Get the output type
	 *
	 * Valid returned types will be:
	 *  - ImagePlane::TYPE_JPEG
	 *  - ImagePlane::TYPE_PNG
	 *  - ImagePlane::TYPE_GIF
	 *
	 * @return string
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getOutType<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">outType</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Process ImagePlane input
	 *
	 * @param array $data
	 * @param string $type ImagePlane::INPUT_POST (default) or ImagePlane::INPUT_TRANSFORMATIONS
	 * @return bool
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> process<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$data</span>, <span style="color: #0000ff;">$type</span> = self::<span style="color: #006600;">INPUT_POST</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
&nbsp;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Set output engine
	 *
	 * @param ImagePlane_Output_Interface $outputEngine
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setOutputEngine<span style="color: #66cc66;">&#40;</span>ImagePlane_Output_Interface <span style="color: #0000ff;">$outputEngine</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">outputEngine</span> = <span style="color: #0000ff;">$outputEngine</span>;
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/**
	 * Get the output engine object
	 *
	 * @return ImagePlane_Output_Interface
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getOutputEngine<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">outputEngine</span>;
	<span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre>
<p>You can see that on my set* functions I return the <code>$this</code> variable. This is called the fluent interface, and it allows you to make calls like <code>$object->method()->method()->method();</code> which makes for compact, and in some cases, semantic code.</p>
<p>You can see that spending just a little bit of time we now have an easily alterable utility class to process uploads from Image Plane with a very low footprint for the actual end user:</p>
<pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #b1b100;">require_once</span> <span style="color: #ff0000;">'../php/imageplane.php'</span>;
spl_autoload_register<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'ImagePlane'</span>,<span style="color: #ff0000;">'autoload'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #0000ff;">$imagePlane</span> = <span style="color: #000000; font-weight: bold;">new</span> ImagePlane<span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> ImagePlane_Output_GD<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #0000ff;">$imagePlane</span>-&gt;<span style="color: #006600;">setOutDirectory</span><span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/dirname"><span style="color: #000066;">dirname</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">__FILE__</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
                -&gt;<span style="color: #006600;">setOutName</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;IPOutput&quot;</span><span style="color: #66cc66;">&#41;</span>
                -&gt;<span style="color: #006600;">setOutType</span><span style="color: #66cc66;">&#40;</span>ImagePlane::<span style="color: #006600;">TYPE_JPEG</span><span style="color: #66cc66;">&#41;</span>
                -&gt;<span style="color: #006600;">process</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$_POST</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;</pre>
<p>Now obviously this literal code snippet presents security issues but they can be tackled. Firstly the above code snippet can easily be moved inside an if block checking for authentication credentials (like an <code>$acl->isLoggedIn()</code> or similar), as well as checking for tokens via the <code>otherData</code> input variable as described in the <a href="http://kitchen.net-perspective.com/docs/image-plane/developer/input#inputVariablesHeader">documentation</a>.</p>
<p>Stay tuned, hopefully I'll be posting more in the future on OO design and provide more complex design topics in the future.</p>
<p>In the mean time if you want an excellent, classic book, I suggest you grab a copy of <a href="http://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional/dp/0201633612">Design Patterns: Elements of Reusable Object-Oriented Software</a> by The Gang of Four.</p>
<p>This post is cross-posted from my personal blog <a href="http://www.toosweettobesour.com/2008/09/13/imageplane-and-some-simple-oop-designs/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/09/13/imageplane-and-some-simple-oop-designs/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/09/13/imageplane-and-some-simple-oop-designs/</feedburner:origLink></item>
		<item>
		<title>Image Plane, As Easy As…</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/G6CUS7bSS1I/</link>
		<comments>http://blog.net-perspective.com/2008/09/10/image-plane-as-easy-as/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 19:38:40 +0000</pubDate>
		<dc:creator>Ryan Bland</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[admin tool]]></category>

		<category><![CDATA[CMS tool]]></category>

		<category><![CDATA[cropping]]></category>

		<category><![CDATA[flash]]></category>

		<category><![CDATA[image application]]></category>

		<category><![CDATA[image editing]]></category>

		<category><![CDATA[Image Plane]]></category>

		<category><![CDATA[image upload]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=110</guid>
		<description><![CDATA[Perhaps not as gifted as <a href="http://en.wikipedia.org/wiki/A2G">more experienced lyricists</a>, but I'll give this ago anyway. In honor of the release of our online image editor:]]></description>
			<content:encoded><![CDATA[<p class="lead">Perhaps not as gifted as <a href="http://en.wikipedia.org/wiki/A2G">more experienced lyricists</a>, but I'll give this a go. In honor of the release of our online image editor:</p>
<p><span id="more-110"></span></p>
<p><strong>A</strong>lready, ambitious adversaries are attempting alternatives to Net Perspective's <a href="http://www.net-perspective.com/work/">achievements</a>. <strong>B</strong>ut a better brainchild beats them back. <strong>C</strong>ertainly, counted among our cleverest creations is the contemporary cropping tool Image Plane. <strong>D</strong>on't doubt its dynamic to deliver image data directly to any dedicated web server. "<strong>E</strong>ffortless easy", "An extremely elastic edifice", are a few expressions elocuted to its excellence. <strong>F</strong>orget forever those foolish, fidgety, and fragile ways of fielding full size images and find this fresh flash file. <strong>G</strong>raciously, <a href="http://kitchen.net-perspective.com/commercial/image-plane/demos/">give it a go</a>.</p>
<p><strong> H</strong>andling how Image Plane output is sized, (width and height) is wholly in the hands of heady developers; however, happy admins have a hold on how images are cropped. <strong>I</strong>magine Image Plane implemented into any internet admin system, and it becomes an invaluable instrument to even inexperienced individuals. <strong>J</strong>ust a juicy gem.</p>
<p><strong> K</strong>indly, <a href="http://kitchen.net-perspective.com/">visit the kitchen</a> and kick it around. <strong>L</strong>ikely, you will love it's light file size, even though <strong>m</strong>any tools and manipulators allow you to make multiple output images. <strong>N</strong>et Perspective knows the needs of <a href="http://www.thinkgeek.com/">nerdy</a> developers and designers, and <strong>o</strong>ur hours of occupational labor originate from our own need for cropping options. <strong>P</strong>racticality is what put Image Plane into practice and pushes the Net Perspective team to perfect its potential. <strong>Q</strong>uite quickly our quality creation will become the quintessential control to your quiver. <strong>R</strong>est assured that reliable support remains ready to registered purchases. <strong>S</strong>o seriously consider securing your copy from our store. <strong>T</strong>hank you for taking the time.</p>
<p><strong> U</strong>se this new utility well and you'll usually underestimate its usefulness. <strong>V</strong>erily a <a href="http://vforvendetta.warnerbros.com/">vast vocabulary</a> reveals the veritable verdict to its versatile <a href="http://dictionary.reference.com/browse/variform">variform</a> output. <a href="http://en.wikipedia.org/wiki/Xhosa"><strong>X</strong>hosa</a> to Zanzibar will set aside xenophobia to examine this Xanadu. <strong>W</strong>e wish that you are willing to welcome it. <strong>Y</strong>our yearly yields may yet convince you.  <strong>Z</strong>ealots who reach zen know this is no zeitgeist it is an image zooming zion, <a href="http://kitchen.net-perspective.com/commercial/image-plane/">so zip on over</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/09/10/image-plane-as-easy-as/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/09/10/image-plane-as-easy-as/</feedburner:origLink></item>
		<item>
		<title>Lessons From Twilight</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/WCrVM8AUw1g/</link>
		<comments>http://blog.net-perspective.com/2008/08/05/lessons-from-twilight/#comments</comments>
		<pubDate>Tue, 05 Aug 2008 21:38:05 +0000</pubDate>
		<dc:creator>R.A.</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[design]]></category>

		<category><![CDATA[process]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=87</guid>
		<description><![CDATA[It's not that I didn't enjoy <a href="http://www.amazon.com/Twilight-Book-1-Stephenie-Meyer/dp/0316160172">the book</a>. I've actually already purchased the next in the series. But, after <a href="http://www.google.com/search?hl=en&#038;q=breaking+dawn+midnight+release&#038;btnG=Search">all the hoopla</a>, I had expected a more satisfying experience.]]></description>
			<content:encoded><![CDATA[<p class="lead">It's not that I didn't enjoy <a href="http://www.amazon.com/Twilight-Book-1-Stephenie-Meyer/dp/0316160172">the book</a>. I've actually already purchased the next in the series. But, after <a href="http://www.google.com/search?hl=en&q=breaking+dawn+midnight+release&btnG=Search">all the hoopla</a>, I had expected a more satisfying experience.</p>
<h3>Stale: Bad for Bread AND Books</h3>
<p>My lack of satisfaction derived from the absence of dynamic figures in the book. I won't get into spoilers, but it is hard for me to imagine living through such a fantastic series of events and being totally unchanged in character. </p>
<p>A good story is one that focuses primarily on the people (vampires, trolls, ants, <em>whatever</em>). The events that unfold are important, but not nearly as important as the life-changing<em>ness</em> of these events on our heroes. This same principle should always apply to designers.</p>
<h3>Opportunities</h3>
<p>One of the interesting side effects of working in the web industry is the broad education we receive from the variety of clients we work with. (I know far more about extracting oil from the ground than is probably strictly necessary.) We are given golden opportunities every project to produce a new product for a new client. Constant reevaluation is crucial to simply stay with the curve.</p>
<p>At the end of it all, when one project is finished and a new one is about to begin, are you the same designer you were? Have your new educational experiences expanded your understanding of your craft? In short, have you changed? If not, you may not be doing your job.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/08/05/lessons-from-twilight/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/08/05/lessons-from-twilight/</feedburner:origLink></item>
		<item>
		<title>Office Space</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/Sr7Z9g9cPIg/</link>
		<comments>http://blog.net-perspective.com/2008/07/30/office-space/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 14:40:15 +0000</pubDate>
		<dc:creator>Carol Paull</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[office space]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=79</guid>
		<description><![CDATA[Task At Hand: Venturing out of <a href="http://www.systekct.com">Systek Computing</a> in search of a new office space that represents Net Perspective]]></description>
			<content:encoded><![CDATA[<p class="lead">Task At Hand: Venturing out of <a href="http://www.systekct.com">Systek Computing</a> in search of a new office space that represents Net Perspective.</p>
<h3>Beginnings</h3>
<p>Net Perspective is currently located in Systek Computing on Texas Avenue in College Station, Texas. For those of you not familiar with <a href="http://www.cstx.gov">College Station</a>, it is home to the main campus of <a href="http://www.tamu.edu">Texas A&amp;M University</a>. How did Net Perspective come to reside in a studio in Systek Computing? </p>
<p>Systek Computing is an IT firm formed back in 1999, from which time the company had offered web design as an additional service to many of its existing clients. Never had web design been taken seriously until myself, Carol Paull, coupled with my colleagues R.A. Ray and Daniel Cousineau joined the web development team. In 2008, we decided to branch off our web development services into a new company, Net Perspective LLC.</p>
<h3>Branching Out</h3>
<p>Net Perspective has become a vital web presence agency here in the Brazos Valley offering our services to local companies in addition to businesses in Houston, Austin, even to San Francisco. We really need an office space to accommodate the growth of our business and brand ourselves in the community. </p>
<p>Tired of the façade of buildings here in College Station, we don’t want to be in just another center. We want our office space and the building we are in to represent our unique style and youth. So our silent investors decided to purchase an empty lot close to our current home to build that eclectic architecture.</p>
<p>Luckily Net Perspective web development team is composed of talented individuals Ryan Bland, Jim Gibbs, and of course R.A. Ray who have all had formal training in design and architecture. With their skills and input coupled with working with an architect of our choice, I’m sure we will be able to design a building that leaves a mark here in College Station and represents our style. So check back from time to time to get an update on the progress of our new home. </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/07/30/office-space/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/07/30/office-space/</feedburner:origLink></item>
		<item>
		<title>Misplaced Creativity</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/O_bJjJ6sWjA/</link>
		<comments>http://blog.net-perspective.com/2008/07/25/misplaced-creativity/#comments</comments>
		<pubDate>Fri, 25 Jul 2008 22:36:19 +0000</pubDate>
		<dc:creator>R.A.</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[creativity]]></category>

		<category><![CDATA[design]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=62</guid>
		<description><![CDATA[Creativity can be a lot like money. Some people have a seemingly unending supply while others possess very little. Money, like creativity, is endowed with no inherent moral value. It can be spent doing great works or frittered away like so many. . . um. . . <em>fritters</em>.]]></description>
			<content:encoded><![CDATA[<p class="lead">Creativity can be a lot like money. Some people have a seemingly unending supply while others possess very little. Money, like creativity, is endowed with no inherent moral value. It can be spent doing great works or frittered away like so many. . . um. . . <em>fritters</em>.</p>
<h3>A Case Study in Failure</h3>
<p>What follows is a picture taken outside of our College Station office. It is also an example of a failure at both ends of the creativity wealth spectrum.</p>
<p><img src="http://blog.net-perspective.com/wp-content/uploads/2008/07/caroncurb.png" alt="" title="Car on a curb" class="aligncenter" /></p>
<p>The failure here began long ago, before the parking lot was even completed. Whether it is the fault of the painter of the lines, the constructor of lot itself, or a law-maker that callously dictated strict widths I am unable to say. Nor does it matter. The fact is that someone in the chain lacked the brain flexibility to properly dimension and we were left with this bastard half-space.</p>
<p>Someone had a creativity deficit. Or, more likely, someone refused to spend some creativity to solve this obvious problem. After all, what is creativity but the ability (or process depending on context) to apply a solution to a given problem?</p>
<p>Unfortunately, sometimes creativity gets in the way of applying the <em>appropriate</em> solution. Our intrepid friend above certainly was able to solve his little problem but few, I think, would consider the result 'appropriate'. </p>
<h3>Get A Context Clue</h3>
<p>Our example is innocuous to be sure, but to me it is a visual reminder of a very common challenge to designers. As people who choose to work in an industry where liberal expenditure is expected we must always be cautious not to let what we want to say get in the way of what our clients <em>need</em> to say.</p>
<p><a href="http://americandesignawards.com/artman/publish/articles/Blog_and_CSS_Only_Sites.shtml">This guy doesn't think we should impose contextual constraints upon ourselves</a>:</p>
<blockquote><p>And to see such talented [designers] jump on the bandwagon created by boring blogoholics, who care more about the words on a page than how it actually looks, is pathetic.</p></blockquote>
<p>Interesting. I was under the impression that what is said and how it is presented were irrevocably intertwined. In fact, I'm <em>enamored</em> of the idea. When it comes to designing for the web, context is everything. We must be judiciously applying our creativity to best affect the "words on the page."</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/07/25/misplaced-creativity/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/07/25/misplaced-creativity/</feedburner:origLink></item>
		<item>
		<title>Time is Money: Save Time With Automation And Phing</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/cGY0h7fPYcI/</link>
		<comments>http://blog.net-perspective.com/2008/07/23/time-is-money-save-time-with-automation/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 16:54:18 +0000</pubDate>
		<dc:creator>Daniel Cousineau</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[automation]]></category>

		<category><![CDATA[best practices]]></category>

		<category><![CDATA[dbdeploy]]></category>

		<category><![CDATA[deployment]]></category>

		<category><![CDATA[phing]]></category>

		<category><![CDATA[php]]></category>

		<category><![CDATA[rsync]]></category>

		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=32</guid>
		<description><![CDATA[I've been talking a lot about automation as of late which led to my <a href="http://www.toosweettobesour.com/2008/05/15/automating-the-development-workflow/">posting</a> a generic, overload broad view of the tools and utilities I use here at Net Perspective. However, I wanted to go into detail about my real world uses of a particular tool, <a href="http://phing.info/">Phing</a>.]]></description>
			<content:encoded><![CDATA[<p class="lead">I've been talking a lot about automation as of late which led to my <a href="http://www.toosweettobesour.com/2008/05/15/automating-the-development-workflow/">posting</a> a generic, overload broad view of the tools and utilities I use here at Net Perspective. However, I wanted to go into detail about my real world uses of a particular tool, <a href="http://phing.info/">Phing</a>.</p>
<p><span id="more-32"></span></p>
<p>In my time with <a href="http://www.net-perspective.com/">Net Perspective</a> (and our previous existence), I've completely dreaded live deployment days because yes, they were full days. An entire day dedicated to waiting for FTP uploades to finish, chmod'ing directories (because Plesk hates me), setting up databases, and testing. All of this despite the fact that we do periodic staging deployments on the same server!</p>
<p>I guess a lot of thanks goes out to <a href="http://www.amazon.com/Pro-PHP-Patterns-Frameworks-Testing/dp/1590598199">Pro PHP: Patterns, Frameworks, Testing, and More</a> by Kevin McArthur. While this book felt more like a Zend Framework tutorial, it did provide a brief introduction to two utilities I use here at work. One of which we care is our focus for the moment: <a href="http://phing.info/">Phing</a>.</p>
<p>Phing is a build environment based on Ant which should be familiar to those in Java world. For those not familiar, Phing uses XML based build files with tags representing tasks and task groupings. At Net Perspective, I use Phing build scripts for everything from packaging up tarballs of utilities we've published (simple jQuery plug-ins, etc.) to <em>automating the live deployment of client sites</em>. I'm particularly happy with the latter as my deployment time has been reduced from a few hours to between 10 minutes max (for a brand new, fresh upload) and about 30 seconds (for an update).</p>
<p>Basic Phing usage is pretty self explanatory, however you may wish to search Google for Phing tutorials or read my post linked above.</p>
<p>Furthermore, my build scripts make use of custom command executions requiring both the execution environment to be *NIX based and for you to read <a href="http://troy.jdmz.net/rsync/index.html">this article</a> on using rsync over ssh without a password (using pre-shared keys).</p>
<h3>Setup</h3>
<p>I start out with 2 files: <strong>build.properties</strong> and <strong>build-live.xml</strong>. I separate live deployment from the default build.xml Phing uses as, even though I harp on automation, live deployments should be manually triggered.</p>
<p>The file build.properties will be our configuration. If you set it up right, you can use the same script for all your projects as long as you alter the build.properties file accordingly. In it I create a few keys that will be necessary.</p>
<pre class="ini">copy.live.<span style="color: #000099;">dir</span>=<span style="color: #660066;">/path/to/site/on/remote/machine</span>
&nbsp;
copy.live.chmod=<span style="color: #933;">&quot;${copy.live.dir}/any/directory&quot;</span>
&nbsp;
copy.live.<span style="color: #000099;">chown</span>=<span style="color: #660066;">user</span>
copy.live.<span style="color: #000099;">chgrp</span>=<span style="color: #660066;">group</span>
&nbsp;
db.live.<span style="color: #000099;">host</span>=<span style="color: #660066;">localhost</span>
db.live.<span style="color: #000099;">user</span>=<span style="color: #660066;">localuser</span>
db.live.<span style="color: #000099;">pass</span>=<span style="color: #660066;">localpass</span>
db.live.<span style="color: #000099;">name</span>=<span style="color: #660066;">localdb</span>
&nbsp;
progs.<span style="color: #000099;">mysql</span>=<span style="color: #660066;">/usr/bin/mysql</span></pre>
<p>You'll notice the properties copy.live.chown and copy.live.chgrp. A problem I encountered is Apache tends to get finicky about web file ownership, so I set this property to whatever user and group would be set after using FTP to upload. This way the final results of the build script will look as if you used FTP (but you didn't, because you're smarter than that).</p>
<p>With my build.properties set, I'll be begin with my build-live.xml. I start out with the basics:</p>
<pre class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="font-weight: bold; color: black;">?&gt;</span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;project</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;Local Project&quot;</span> <span style="color: #000066;">default</span>=<span style="color: #ff0000;">&quot;dist&quot;</span> <span style="color: #000066;">basedir</span>=<span style="color: #ff0000;">&quot;.&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;tstamp</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;property</span> <span style="color: #000066;">file</span>=<span style="color: #ff0000;">&quot;./build.properties&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/project<span style="font-weight: bold; color: black;">&gt;</span></span></span></pre>
<p>The <strong>&lt;tstamp /&gt;</strong> initializes the ${DSTAMP} and ${TSTAMP} properties and the <strong>&lt;property file="./build.properties" /&gt;</strong> obviously includes our build.properties file.</p>
<p>Continuing along I create my default build target <strong>dist</strong> to just reference a few external targets:</p>
<pre class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;dist&quot;</span> <span style="color: #000066;">depends</span>=<span style="color: #ff0000;">&quot;copy,clean,chmod&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/target<span style="font-weight: bold; color: black;">&gt;</span></span></span></pre>
<h3>Upload</h3>
<p>Now we begin the fun part, assuming you've already followed the link above about setting up a pre-shared ssh key, we can create our copy target which will be responsible for uploading new/changed files to the server:</p>
<pre class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;copy&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;exec</span> <span style="color: #000066;">command</span>=<span style="color: #ff0000;">&quot;rsync -aCz -e 'ssh -i /path/to/ssh/preshared/key' ${project.basedir}/path/to/local/files remoteuser@remoteserver:${copy.live.dir}/httpdocs/&quot;</span> <span style="color: #000066;">escape</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/target<span style="font-weight: bold; color: black;">&gt;</span></span></span></pre>
<p>The key awesomeness is obviously our rsync command. Our particular variant contains the -C flag which ignores CVS/SVN type files (in particular, .svn folders) and omits the -v verbosity flag.</p>
<h3>Cleanup</h3>
<p>Next we need to build a clean target that will clear any compiled/cache directories, set ownerships, and generally clean house:</p>
<pre class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;clean&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;echo</span> <span style="color: #000066;">msg</span>=<span style="color: #ff0000;">&quot;Clearing Compiled...&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;exec</span> <span style="color: #000066;">command</span>=<span style="color: #ff0000;">&quot;ssh -i /path/to/ssh/preshared/key remoteuser@remotehost rm -rf ${copy.live.dir}/httpdocs/delete/contents/*&quot;</span> <span style="color: #000066;">escape</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;echo</span> <span style="color: #000066;">msg</span>=<span style="color: #ff0000;">&quot;Changing PROJECT_STATUS to live...&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;exec</span> <span style="color: #000066;">command</span>=<span style="color: #ff0000;">&quot;ssh -i /path/to/ssh/preshared/key remoteuser@remotehost &amp;quot;sed -r -i 's/define\(\W*''PROJECT_STATUS''\W*,\W*''(.+?)''\W*\);/define\( '\''PROJECT_STATUS'\'', '\''live'\'' \);/g' ${copy.proof.admin.dir}/path/to/config.file.php&amp;quot;&quot;</span> <span style="color: #000066;">escape</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/target<span style="font-weight: bold; color: black;">&gt;</span></span></span></pre>
<p>Here in our first exec task, rather than running rsync, we use ssh and our pre-shared key to run a command on our remote machine. In this case an rm -rf to clear our a particular directory (could be a /cache, /compiled, depends on your setup). In our second exec task you'll notice some uglies involving parenthesis escaping, however what we are essentially doing is running <em>sed</em> on the remote machine to flip a configuration value. What we do is maintain the configuration for all stages of deployment so that to change between the 2 or 3 stages it is just a single constant being changed.</p>
<h3>Ownership</h3>
<p>Finally we need to set ownerships of all the files so that Apache will play nice:</p>
<pre class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;target</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;chmod&quot;</span><span style="font-weight: bold; color: black;">&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;echo</span> <span style="color: #000066;">msg</span>=<span style="color: #ff0000;">&quot;Setting Ownership...&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;exec</span> <span style="color: #000066;">command</span>=<span style="color: #ff0000;">&quot;ssh -i /path/to/ssh/preshared/key remoteuser@remotehost chown -R ${copy.live.chown}:${copy.live.chgrp} ${copy.live.dir}/path/to/dir/*&quot;</span> <span style="color: #000066;">escape</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;echo</span> <span style="color: #000066;">msg</span>=<span style="color: #ff0000;">&quot;Setting Write Permissions...&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
       <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;exec</span> <span style="color: #000066;">command</span>=<span style="color: #ff0000;">&quot;ssh -i /path/to/ssh/preshared/key remoteuser@remotehost chmod 777 ${copy.live.chmod}&quot;</span> <span style="color: #000066;">escape</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="font-weight: bold; color: black;">/&gt;</span></span>
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/target<span style="font-weight: bold; color: black;">&gt;</span></span></span></pre>
<p>Here we just use ssh and our pre-shared key to execute chown to match owner and group to that of what the particular site uses (or apache:apache) and to 777 certain folders (like upload folders, etc.).</p>
<h3>Concluding Remarks</h3>
<p>Using the rsync over ssh and one-line ssh techinques above you can do more complicated tasks like <a href="http://www.davedevelopment.co.uk/2008/04/14/how-to-simple-database-migrations-with-phing-and-dbdeploy/">DBDeploy</a> on a live server that denies external access to its databases (PROTIP: rsync the db folder, build.properties, and a copy of the build script containing the migrate task to a folder outside of the publicly visible httpdocs and use the ssh trick to invoke Phing and the migrate task).</p>
<p>If you have your application set up appropriately you can modify the upload tasks to have rsync use the --delete flag to ensure perfect synchronization (files deleted locally are deleted remotely as well). A caveat is if you do not ignore generated content directories (like user uploaded images), those will be deleted as well.</p>
<p>And finally, even if you dislike Phing as a build environment, since I'm manually passing commands you could feasibly convert all my commands to a simple .sh script or apply them to any other build environment you desire.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/07/23/time-is-money-save-time-with-automation/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/07/23/time-is-money-save-time-with-automation/</feedburner:origLink></item>
		<item>
		<title>Publishing &amp; Purpose</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/1mrhOQAB7EY/</link>
		<comments>http://blog.net-perspective.com/2008/07/17/publishing-and-purpose/#comments</comments>
		<pubDate>Thu, 17 Jul 2008 20:42:06 +0000</pubDate>
		<dc:creator>R.A.</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[design]]></category>

		<category><![CDATA[introduction]]></category>

		<category><![CDATA[publishing]]></category>

		<category><![CDATA[purpose]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=22</guid>
		<description><![CDATA[Issues of transparency and marketing are certainly at the forefront, but <a href="http://blog.net-perspective.com/2008/07/17/inaugural-blog/">as my colleague alluded to</a>, the overriding purpose of this space is still largely amorphous. The simple answer is that we have things we want to communicate to the (for now) faceless public and a vehicle for doing so became a necessity.]]></description>
			<content:encoded><![CDATA[<p class="lead">Issues of transparency and marketing are certainly at the forefront, but <a href="http://blog.net-perspective.com/2008/07/17/inaugural-blog/">as my colleague alluded to</a>, the overriding purpose of this space is still largely amorphous. The simple answer is that we have things we want to communicate to the (for now) faceless public and a vehicle for doing so became a necessity.</p>
<p><span id="more-22"></span></p>
<h3>I Don't Live to Write, But&hellip;</h3>
<p>The written word is probably the articulate human's most powerful tool for idea conveyance. Generally free as it is, in the best cases, from aesthetic bias, tonal slanting, and other trappings of the spoken word, these objective little marks have the power to influence ideas and ideals for centuries or even millennia. It's a wonderful system.</p>
<p>This isn't the world I live in really. In my world, someone else is usually doing the writing and my job is to get you to read it or buy it and, we hope, respond to it. My role is to help tell someone else's story.</p>
<p>This project therefore, is enormously cathartic. Here I get to tell my story, which really means <a href="http://www.net-perspective.com/">our story</a>, as much with the visually communicative as the textual. Designing for oneself is quite revealing and not a little autobiographical. </p>
<h3>Setting Sail</h3>
<p>The maiden design for this site is unlike anything I've constructed before. The layout is almost purely typographic, the inspiration for which comes in no small part via <a href="http://www.jasonsantamaria.com/">Jason Santa Maria's recent redesign</a> of his own blog. Not that I'm trying to do <a href="http://jasonsantamaria.com/articles/variation-within-constraints/">what he is</a>; our purposes are too dissimilar. But, that which is both beautiful and might someday be considered revolutionary should be lauded. So we laud.</p>
<p>And also we design, and develop, and build, and grow for these are the things for which we were reared. In time we hope to make this almost inherently obvious.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/07/17/publishing-and-purpose/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/07/17/publishing-and-purpose/</feedburner:origLink></item>
		<item>
		<title>Inaugural Blog</title>
		<link>http://feedproxy.google.com/~r/net-perspective/~3/SsdgbO258fg/</link>
		<comments>http://blog.net-perspective.com/2008/07/17/inaugural-blog/#comments</comments>
		<pubDate>Thu, 17 Jul 2008 17:31:53 +0000</pubDate>
		<dc:creator>Daniel Cousineau</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[company blog]]></category>

		<category><![CDATA[introduction]]></category>

		<category><![CDATA[social networking]]></category>

		<guid isPermaLink="false">http://blog.net-perspective.com/?p=10</guid>
		<description><![CDATA[It is quite possibly the greatest day in the history of the internet, by our powers combined: this is the Net Perspective Blog.]]></description>
			<content:encoded><![CDATA[<p class="lead">It is quite possibly the greatest day in the history of the internet, by our powers combined: this is the Net Perspective Blog.</p>
<p><span id="more-10"></span></p>
<p>Company blogging is something I used to regard as a lame attempt of a marketing department to seem hip or cool. Engagement and actual interaction with their target audience was the furthest thing from their mind, as it seemed that these marketing people saw blogs as this magic new fad where potential customers came out of nowhere to read just because it was a blog. For a while this may have been partially true; however, these marketers soon learned their folly as traffic never materialized and their 'blogs' were poked fun at by the masses.</p>
<p>A <a href="http://lenovoblogs.com/">few</a> <a href="http://particletree.com/">blogs</a> stand as a shining example to corporate blogging. In these blogs I find frank discussions of marketing methods, internal insights to design and engineering decisions, and informative posts that not only help me in my own endeavors, but show off the competency and creativeness of the individuals that make up the company in question.</p>
<p>I wanted to show off too!</p>
<p>As a result, I'm proud to present to you the Net Perspective company blog. You can expect to hear from myself on programming and server side related issues, from R.A. Ray on design related topics, and you may even hear occasionally from our team on topics of interest.</p>
<p>For now you can follow us by subscribing to our <a href="http://blog.net-perspective.com/feed/">RSS feed</a>, or you can follow our company on a few social networks like <a href="http://twitter.com/netperspective">Twitter</a>, <a href="http://www.plurk.com/user/netperspective">Plurk</a>, <a href="http://www.last.fm/user/netperspective">Last.fm</a>, and <a href="http://www.facebook.com/pages/Net-Perspective/7868537132">Facebook</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.net-perspective.com/2008/07/17/inaugural-blog/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.net-perspective.com/2008/07/17/inaugural-blog/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic Page Served (once) in 1.183 seconds --><!-- Cached page served by WP-Cache -->

