<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Phatness.com</title>
	
	<link>http://phatness.com</link>
	<description>- Still kickin</description>
	<lastBuildDate>Thu, 26 Aug 2010 14:42:52 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/phatness" /><feedburner:info uri="phatness" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>App Store Review Process</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/QyROQpcgO9c/</link>
		<comments>http://phatness.com/2010/08/app-store-review-process/#comments</comments>
		<pubDate>Thu, 26 Aug 2010 14:41:02 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Computers]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2208</guid>
		<description><![CDATA[Submitted a fairly large iPhone app to the App Store.  Look at this:
Hello Mike,
Thank you for submitting BounceOff 1.0 to the App Store.
We’ve completed the review of your application but this version cannot be posted to the App Store because it crashes when the user searches for a name or email without any contacts [...]]]></description>
			<content:encoded><![CDATA[<p>Submitted a fairly large iPhone app to the App Store.  Look at this:</p>
<blockquote><p>Hello Mike,</p>
<p>Thank you for submitting BounceOff 1.0 to the App Store.</p>
<p>We’ve completed the review of your application but this version cannot be posted to the App Store because it crashes when the user searches for a name or email without any contacts on their device. We have included additional details below to help explain the issue, and hope you’ll consider revising and resubmitting your application.</p>
<p>Using iPhone 3GS running iOS 4.0.2, here is how we found this crash:</p>
<p>Steps to reproduce:</p>
<p>1. Open the application<br />
2. Select the &#8220;Buckets&#8221; tab<br />
3. Select a Bucket<br />
4. Select &#8220;Invite People&#8221;<br />
5. If user has no contacts on the phone, and starts to type a name or an email, the application crashes.</p>
<p>We have attached detailed crash logs to help. If you need information on how to read crash logs, you may want to review the following TechNote: http://developer.apple.com/iphone/library/technotes/tn2008/tn2151.html</p>
<p>If you have any questions about this response, or would like to discuss it further, please feel free to reply to this email. We look forward to reviewing your revised app.</p>
<p>Sincerely,</p>
<p>App Review Team</p></blockquote>
<p>That was the rejection email from the AppStore.  I&#8217;m entirely exasperated at myself for missing this bug.  (You idiot, you should know there are people with no contacts on the phone!)</p>
<p>I am completely taken aback and amazed at how detailed this report from Apple is.  I don&#8217;t get this kind of detail from team members!  I fully expected a crashing app to be simply rejected with a statement along the lines of &#8220;It crashes,  you idiot.&#8221;  So this is truly great.  Even more impressive is that it only took them less than an hour to get back to us once the app went into review.  I&#8217;m completely happy at how they handled that.  Kudos Apple.</p>
<p>However, what is not impressive: IT TOOK 8 DAYS TO GO INTO REVIEW.  Yes, I submitted on Thursday morning.  On Friday afternoon of the next week, it was reviewed.  I guess, having a gate keeper wouldn&#8217;t be as bad if they didn&#8217;t take so long to get your app into review.</p>
<p>We are on day four of our resubmission.  I fear that it will take another 8 days to go into review again.  All reports from the experts (aka, chockenberry: <a href="http://appdevmanual.com/" target="_blank">http://appdevmanual.com/</a> ) say that you go back to the end of the line.  Instead, it would be nice if it was more of a sliding scale.  Say once resubmitted on the first rejection, you get put right back in for immediate review.  In the case of further rejections, you go back farther and farther back in the line for each rejection.  Even some variation on that.  First time, we let you slide back in.  Every other time, back to the end of the line.</p>
<img src="http://feeds.feedburner.com/~r/phatness/~4/QyROQpcgO9c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/08/app-store-review-process/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/08/app-store-review-process/</feedburner:origLink></item>
		<item>
		<title>How to Make Your Website Images Look Great on iPhone 4’s High-DPI Screen</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/3_s-qp8N0jo/</link>
		<comments>http://phatness.com/2010/07/how-to-make-your-website-images-look-great-on-iphone-4s-high-dpi-screen/#comments</comments>
		<pubDate>Thu, 08 Jul 2010 13:25:35 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Computers]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2200</guid>
		<description><![CDATA[I picked up an iPhone 4.  How?
I woke up at 3 AM the morning Apple started taking reservations.  That day their store was having troubles taking orders.  I kept checking almost every hour until I finally got a reserved phone at 10 AM.
On the June 24th, a friend and I got to [...]]]></description>
			<content:encoded><![CDATA[<p>I picked up an iPhone 4.  How?</p>
<p>I woke up at 3 AM the morning Apple started taking reservations.  That day their store was having troubles taking orders.  I kept checking almost every hour until I finally got a reserved phone at 10 AM.</p>
<p>On the June 24th, a friend and I got to the mall with the Apple Store at 6:45.  The parking lot was empty, except for maybe 6 cars.  I thought, great, Michigan&#8217;s economy might actually pay off this time.  When we opened the doors, I was wrong.  Apparently the hundreds to thousands of people parked in the back.</p>
<p>I waited in line for 4 hours and 15 minutes before I finally had my phone in my hand.  I will NEVER DO THAT AGAIN.</p>
<p>Send it to my house next time.</p>
<p>The first thing you notice about the phone is that screen.  That unbelievable screen.  Oh yeah, and how it makes just about every image on the web look like shit.  Well, if you are a website owner, there are some things you can do to make your website look better.  Text is fine already.  But you have to swap out your images for higher resolution counterparts.</p>
<p>The technique is only supported in the newest browsers.  But so what?  Who will be running IE 6 on an Android (You can be sure that Android handset makers will follow) or an iPhone?</p>
<p>From the solution I posted at Flowz:</p>
<blockquote><p>The trick here is that we check to see if the font size for our special class is set to value declared in our high-DPI CSS file. (Our flag) It will only be set if the browser passed the media query. If the flag is set, grab every element in the DOM with the replace-2x class and change the src attribute to point to our high-res counterparts.</p></blockquote>
<p>Go check it out:<br />
<a href="http://flowz.com/2010/07/css-image-replacement-for-iphone-4-high-dpi-retina-display/" target="_blank">http://flowz.com/2010/07/css-image-replacement-for-iphone-4-high-dpi-retina-display/</a></p>
<img src="http://feeds.feedburner.com/~r/phatness/~4/3_s-qp8N0jo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/07/how-to-make-your-website-images-look-great-on-iphone-4s-high-dpi-screen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/07/how-to-make-your-website-images-look-great-on-iphone-4s-high-dpi-screen/</feedburner:origLink></item>
		<item>
		<title>N.A.D.D. Neutralizer</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/__GoRtCzPfY/</link>
		<comments>http://phatness.com/2010/04/nadd-neutralizer/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 13:50:44 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Grails Tips]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2184</guid>
		<description><![CDATA[After starting up another Grails project and completely missing my text-to-speech solution for long build times, I decided to do something a little more re-usable.
I just released a Grails plugin that provides this functionality.  It&#8217;s as simple as: 
grails install-plugin nadd-neutralizerRight now, only Mac OS X is supported.  Patches are welcome for other operating [...]]]></description>
			<content:encoded><![CDATA[<p>After starting up another Grails project and completely missing <a href="http://phatness.com/2010/02/decrease-latency-on-grails-builds/">my text-to-speech solution for long build times</a>, I decided to do something a little more re-usable.</p>
<p>I just released a Grails plugin that provides this functionality.  It&#8217;s as simple as: </p>
<p><code>grails install-plugin nadd-neutralizer</code>Right now, only Mac OS X is supported.  Patches are welcome for other operating systems.  Source code is here: http://github.com/digerata/grails-nadd-neutralizer</p>
<img src="http://feeds.feedburner.com/~r/phatness/~4/__GoRtCzPfY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/04/nadd-neutralizer/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/04/nadd-neutralizer/</feedburner:origLink></item>
		<item>
		<title>How to Externalize Your Grails Configuration Like a Professional</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/zTev_vHzi_w/</link>
		<comments>http://phatness.com/2010/03/how-to-externalize-your-grails-configuration/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 15:14:30 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Grails Tips]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2151</guid>
		<description><![CDATA[Grails docs go a long way towards being the only materials you need to learn how to use Grails.  Unfortunately, it can miss a few things that are common use cases.
In any real world production app, you don&#8217;t manage your configuration from within your WAR file.  How do you have a configuration file [...]]]></description>
			<content:encoded><![CDATA[<p>Grails docs go a long way towards being the only materials you need to learn how to use Grails.  Unfortunately, it can miss a few things that are common use cases.</p>
<p>In any real world production app, you don&#8217;t manage your configuration from within your WAR file.  How do you have a configuration file deployed out to your production server beside your WAR file?</p>
<p>Most of the posts out there about external configuration all talk about hard coding external config locations into a variable like so:</p>
<pre>grails.config.locations = [ "file:${userHome}/${appName}-conf.properties"]</pre>
<p>Well, that sucks.  That is assuming, again, more about production then you really can afford.  The configuration of the production system, isn&#8217;t up to the developer.  It&#8217;s up to the Release Manager or System Admin or a whole team of people besides you.  Rather than force them into accommodating you, the programmer, you need to make it easy for them to specify WHATEVER THE FUCK THEY WANT.<br />
<span id="more-2151"></span><br />
So here it is, place the following in Config.groovy:</p>
<pre>def ENV_NAME = "APPNAME_CONFIG"
if(!grails.config.location || !(grails.config.location instanceof List)) {
	grails.config.location = []
}
if(System.getenv(ENV_NAME)) {
	println "Including configuration file specified in environment: " + System.getenv(ENV_NAME);
	grails.config.location &lt;&lt; "file:" + System.getenv(ENV_NAME)

} else if(System.getProperty(ENV_NAME)) {
	println "Including configuration file specified on command line: " + System.getProperty(ENV_NAME);
	grails.config.location &lt;&lt; "file:" + System.getProperty(ENV_NAME)

} else {
	println "No external configuration file defined."
}</pre>
<p>The key points in this method that are not in the docs or blogs to come before me:</p>
<ul>
<li>It actually works.  It appears some devs don&#8217;t bother testing their methods before posting the code.  You have to initialize the grails.config.location as a list if it isn&#8217;t already.  And it is grails.config.location.  Not, location[s].</li>
<li>This method is flexible, it allows either the config location to be specified in the OS Environment or on the command line.  You don&#8217;t know what is available to you in production!</li>
<li>Perhaps the most important: It tells the person starting up the application, what configuration the app will be using.  There is nothing more frustrating than being in the heat of a deployment, already stretched to the edge of your maintenance window, and being unable to find out why your configuration changes aren&#8217;t taking affect.
<li>It uses println statements instead of log statements.  In my usage, logging wasn&#8217;t setup yet so println it was.  I&#8217;m sure with some fiddling those could be replaced with log statements.</li>
<li>If I sound harsh, it&#8217;s because I&#8217;ve just dealt with another stupid Grails issue that should be a no brainer.  And if not in the official documentation, the 3 or 4 blog posts and a Stack Overflow question about this should have provided the CORRECT FUCKING ANSWER.</li>
</ul>
<img src="http://feeds.feedburner.com/~r/phatness/~4/zTev_vHzi_w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/03/how-to-externalize-your-grails-configuration/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/03/how-to-externalize-your-grails-configuration/</feedburner:origLink></item>
		<item>
		<title>Decrease “Latency” on Grails Builds</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/wfO9aicMHRQ/</link>
		<comments>http://phatness.com/2010/02/decrease-latency-on-grails-builds/#comments</comments>
		<pubDate>Wed, 24 Feb 2010 14:56:37 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2125</guid>
		<description><![CDATA[This is a tip for those of you dealing with long build times, which for me, is anything greater than about 4 seconds  
The problem that those of us with NADD face is the second we are waiting for something to finish, we [alt&#124;cmd]+Tab to a browser and start reading slashdot, rotten tomatoes, daringfireball, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://xkcd.com/303/"><img class="alignright" src="http://imgs.xkcd.com/comics/compiling.png" border="0" alt="" /></a>This is a tip for those of you dealing with long build times, which for me, is anything greater than about 4 seconds <img src='http://phatness.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>The problem that those of us with <a href="http://www.randsinrepose.com/archives/2003/07/10/nadd.html">NADD</a> face is the second we are waiting for something to finish, we [alt|cmd]+Tab to a browser and start reading slashdot, rotten tomatoes, daringfireball, or any of a million other sites.  Likely, you classify this &#8220;quick field trip&#8221; as multitasking and because you are so very good at multitasking (despite what all the <a href="http://en.wikipedia.org/wiki/Human_multitasking">experts say</a>), you disregard the fact that your build was probably finished 10 minutes ago.<br />
<span id="more-2125"></span><br />
Well, I finally came to grips with these facts:</p>
<p>- I cannot multitask.  I can only context switch.  And user-to-kernel-to-user is getting slower in my old age.<br />
- Half the time I&#8217;m looking at my browser, I&#8217;m flipping back to see if the build has finished.  Further exacerbating the context switch problem.<br />
- I cannot bring myself to firewall off my favorite, &#8220;industry news&#8221; sites.</p>
<p>So with that, I decided to fix what I could.  That is, decreasing my &#8220;response latency&#8221; for &#8220;asynchronous tasks.&#8221;  You&#8217;ll need to be running on a Mac.  But you&#8217;re a super leet programmer so I&#8217;m sure you already are.  OS X has a frickin&#8217; awesome text-to-speech capability.  Bundled along with that is a command line app: say.</p>
<p>Try it out, type at the terminal: say &#8220;Why didn&#8217;t I think of that?&#8221;</p>
<p>Now, for those of you who remember <a href="http://en.wikipedia.org/wiki/Dr._Sbaitso">Dr. Spaitso</a>, you probably just shit yourself at how great the default voice sounds.  (Though, if you are my wife, you are dully unimpressed.)</p>
<p>So I&#8217;m sure you see where I&#8217;m going with this.  Let&#8217;s get down to it.</p>
<p>Open up your GRAILS_PROJECT/scripts/Events.groovy file, add the following:</p>
<pre class="js">eventStatusFinal = { msg -&gt;

    String.metaClass.say = {
        ["osascript", "-e", "tell application \"iTunes\" to set sound volume to 30"].execute()
        sleep(300)
        "say \"${delegate}\"".execute().waitFor()
        ["osascript", "-e", "tell application \"iTunes\" to set sound volume to 100"].execute()
    }

    if(msg.startsWith("Server running.")) {
        "Application is running".say()
    } else {
        msg.say()
    }
}</pre>
<p>I made this a metaClass option originally because it came from a groovy bootstrap groovy script.  You could just as easily make it a local closure or method.</p>
<p>The gist is that every time an event completes, it will read aloud the status line.  But first, it turns down the music playing in itunes.  (It just so happens that I have iTunes turned all the way up and use the system volume to regulate.  If you don&#8217;t do that, you will probably have to adjust the volume values)</p>
<p>Pretty neat!  I actually use this in some fashion in all my projects now&#8230; maven, ant, even xcode.  It really helps.</p>
<p><strong>Update:</strong> I created a Grails plugin that handles this all for you: <a href="http://phatness.com/2010/04/nadd-neutralizer/">http://phatness.com/2010/04/nadd-neutralizer/</a>.</p>
<img src="http://feeds.feedburner.com/~r/phatness/~4/wfO9aicMHRQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/02/decrease-latency-on-grails-builds/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/02/decrease-latency-on-grails-builds/</feedburner:origLink></item>
		<item>
		<title>Grails Newbie Mistakes &amp; Gotchas</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/kp8LZ7Z53_o/</link>
		<comments>http://phatness.com/2010/02/grails-newbie-mistakes-gotchas/#comments</comments>
		<pubDate>Tue, 23 Feb 2010 17:41:53 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Grails Tips]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2106</guid>
		<description><![CDATA[Whew, Grails has some gotchas.  It is so great for so many reasons.  But WOW!  There are some time sinks tucked away for you to discover.  In the hope of helping others, here is a list of the ones that hit me.

Constraints!  HasErrors!
Never, EVER forget to add constraints to your [...]]]></description>
			<content:encoded><![CDATA[<p>Whew, Grails has some gotchas.  It is so great for so many reasons.  But WOW!  There are some time sinks tucked away for you to discover.  In the hope of helping others, here is a list of the ones that hit me.<br />
<span id="more-2106"></span></p>
<h2>Constraints!  HasErrors!</h2>
<p>Never, EVER forget to add constraints to your composited domain model at the same time you forget to check hasErrors after save.  Grails will not tell you when your domain.save() fails.  When in doubt, pass failOnError:true to your save() calls.</p>
<p>Where would this hit you?  Most of the time scaffolding takes care of your db operations.  But, it happened to me in several places.  When I was loading a default set of data in Bootstrap.groovy, I never saw my new objects showing up.  The other, more devious situation was when I was using the Nimble plugin and extending the User object Nimble provides with some dependent classes.  I kept getting the wicked &#8220;hibernate transient &#8211; must save&#8221; exception.  Lastly, most of the time you are wrapping your CRUD in services, you will need to watch out for this.</p>
<h2>Watch That Naming!</h2>
<p>Many times I&#8217;ll create a class manually in the appropriate bucket for what I want to do.  For example, instead of going through grails create-integration-test package.Class, I&#8217;ll just go create a new class under $GRAILS_APP/tests/integration/package.  I spent a good hour trying to figure out why my integration test was not being run.  And then I found it.  I named my test ClassNameTest.groovy.  When it should be ClassNameTest<strong>[s]</strong>.groovy!  Doh!</p>
<h2>Grails Interactive</h2>
<p>The second you have a few maven dependencies and/or plugin dependencies, it can take grails multiple seconds (On average, 3 for me) just to resolve the dependencies of your app.  This is a serious flaw in Ivy (the underlying dependency management grails uses).  Unfortunately, this is what we are stuck with.  Run grails interactive to speed things up.  The JVM starts up and keeps running after each command.  (The dependency checks go away, but things are still slow.)  Further, regardless of how high you specify max memory, it still fails with out of memory errors every few run-app cycles.  There must be a few leaks still laying around.</p>
<h2>File Uploads</h2>
<p>Something no one tells you and is found no where on the grails.org documentation is how to get the true filename of an uploaded file.  If you just do what the docs tell you via:</p>
<pre class="js">def uploadedFile = request.getFile("file")
uploadedFile.name</pre>
<p>the result is that the filename is &#8220;file&#8221;.  Yes, real fucking useful!</p>
<p>Use, instead:</p>
<pre class="js">def uploadedFile = request.getFile("file")
uploadedFile.originalFilename</pre>
<h2>Leveraging established Java codebase</h2>
<p>One of the best aspects of Groovy, in my eyes, is being able to leverage Java.  Grails goes further and allows you to specify remote maven artifacts your app depends on.  This is great.  Until you want to reuse Java domain objects.</p>
<p>You see, GORM doesn&#8217;t support mapping both Groovy and Java objects if either of those objects refer to each other.  So you can&#8217;t have a Groovy domain object extend a Java object.  You can&#8217;t have a Groovy domain object contain a Java domain object.  There is an issue open on this:</p>
<p><a href="http://jira.codehaus.org/browse/GRAILS-4996">http://jira.codehaus.org/browse/GRAILS-4996</a></p>
<p>I&#8217;m bringing this up here because this limitation definitely isn&#8217;t documented anywhere.  And I didn&#8217;t discover it until step 98 out of 100 in integrating my codebases.</p>
<p>Further, I found that GORM errors are a bit limited in some circumstances (this one).  If you hit a problem where GORM is throwing a cryptic message, and it is about a object in your hasMany map, try removing the hasMany and adding it as a single relationship.  The error message gets much more verbose.</p>
<p>(if hasMany, move it to a single to get a better error message from hibernate)</p>
<pre class="js">
class Tool {
	//static hasMany = [ widgets : Widget, rocks : com.acme.crud.Rock ]
	static hasMany = [ widgets : Widget ]
	Rock rock
	String name
</pre>
<h2>Never *ever* use reserved variables in UrlMappings.</h2>
<p>Wait, there are reserved variable names?  Yeah, that&#8217;s what I said!  Say you have a parameter your controller needs called action.  $action actually maps to the function in your controller that will be called.  So if you use this, suddenly, no request will get to your controller.  (Unless it just so happens the type you enter in the URL exists as a function.)  This happens even if you use the extended UrlMapping syntax where you can specify the action you want to use.  In my case:</p>
<pre class="js">
"/download/$id/$version/$preview/$action/$filename" {
			controller = "downloadController"
			action = "index"
			constraints {

			}
		}
</pre>
<p>On no, don&#8217;t do that!  Change $action to something else instead.</p>
<img src="http://feeds.feedburner.com/~r/phatness/~4/kp8LZ7Z53_o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/02/grails-newbie-mistakes-gotchas/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/02/grails-newbie-mistakes-gotchas/</feedburner:origLink></item>
		<item>
		<title>How to Use Test Files in Grails</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/-NsC62n6lLM/</link>
		<comments>http://phatness.com/2010/02/grails-test-files/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 16:29:38 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Grails]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Grails Tips]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2099</guid>
		<description><![CDATA[I&#8217;m embarking, balls-out, on a new project using Grails.  I&#8217;ll be leveraging a significant portion of our Java codebase and the fact that I can do that,is just plain stellar.
It quickly came time to test out some of the integration.  The very first question was how to load resources for testing.  E.g., [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m embarking, balls-out, on a new project using Grails.  I&#8217;ll be leveraging a significant portion of our Java codebase and the fact that I can do that,is just plain stellar.</p>
<p>It quickly came time to test out some of the integration.  The very first question was how to load resources for testing.  E.g., I have a service that handles file uploads.  How do I pass it a test file?</p>
<p>The documentation isn&#8217;t straightforward on this.  In fact, I found the solution attached to a bug report for grails 1.1.  It&#8217;s pretty simple, once you pull in the spring packages:</p>
<pre class="js">
import org.springframework.core.io.ClassPathResource
import org.springframework.core.io.Resource
</pre>
<p>And then in your testXXX() function:</p>
<pre class="js">
Resource resource = new ClassPathResource("resources/crying-baby.jpg")
def file = resource.getFile()
assert file.exists()
</pre>
<p>And you are good to go.  Note the assert at the end to verify things are working.</p>
<img src="http://feeds.feedburner.com/~r/phatness/~4/-NsC62n6lLM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/02/grails-test-files/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/02/grails-test-files/</feedburner:origLink></item>
		<item>
		<title>SMF: Solr</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/kr1VWCo9HNo/</link>
		<comments>http://phatness.com/2010/02/smf-solr/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 18:58:23 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[System Admin]]></category>
		<category><![CDATA[Linux To Solaris]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2092</guid>
		<description><![CDATA[Setting up Solr was a bit different then the others.  Solr&#8217;s distribution is multifaceted, containing multiple server examples, client code, as well as, a simple production ready server.  So let me start off with a few steps I took in setting up Solr.


Download and extract latest binary from solr website.
Within solr folder is [...]]]></description>
			<content:encoded><![CDATA[<p>Setting up Solr was a bit different then the others.  Solr&#8217;s distribution is multifaceted, containing multiple server examples, client code, as well as, a simple production ready server.  So let me start off with a few steps I took in setting up Solr.<br />
<span id="more-2092"></span></p>
<ol>
<li>Download and extract latest binary from solr website.</li>
<li>Within solr folder is examples/</li>
<li>Remove example-DIH/</li>
<li>Remove exampledocs/</li>
<li>Create directory /opt/local/share/solr-VERSION (solr-1.4 at time of this writing)</li>
<li>Copy contents of examples to /opt/local/share/solr-VERSION</li>
<li>Create a symlink /opt/local/share/solr-VERSION -&gt; solr</li>
</ol>
<p>And here is the SMF:</p>
<pre class="html">&lt;?xml version='1.0'?&gt;
&lt;!DOCTYPE service_bundle SYSTEM
'/usr/share/lib/xml/dtd/service_bundle.dtd.1'&gt;

&lt;service_bundle type='manifest' name='Solr'&gt;

&lt;service
	name='network/solr'
	type='service'
	version='1'&gt;

	&lt;create_default_instance enabled='false'/&gt;
    &lt;single_instance/&gt;

	&lt;dependency name='fs'
		grouping='require_all'
		restart_on='none'
		type='service'&gt;
		&lt;service_fmri
			value='svc:/system/filesystem/local'/&gt;
    &lt;/dependency&gt;

    &lt;dependency name='net'
		grouping='require_all'
		restart_on='none'
		type='service'&gt;
		&lt;service_fmri value='svc:/network/loopback'/&gt;
    &lt;/dependency&gt;

    &lt;dependent name='solr_multi-user'
	 	grouping='optional_all'
		restart_on='none'&gt;
		&lt;service_fmri value='svc:/milestone/multi-user'/&gt;
    &lt;/dependent&gt;

    &lt;exec_method
		name='start'
		type='method'
		exec='/opt/local/lib/svc/method/svc-solr'
		timeout_seconds='60'&gt;

		&lt;method_context working_directory='/opt/local/share/solr'&gt;
        	&lt;method_credential user='root' group='root' /&gt;
      	&lt;/method_context&gt;
    &lt;/exec_method&gt;

    &lt;exec_method
		name='stop'
		type='method'
		exec=':kill'
		timeout_seconds='60'&gt;
    &lt;/exec_method&gt;

	&lt;template&gt;
		&lt;common_name&gt;
			&lt;loctext xml:lang='C'&gt;
				solr
			&lt;/loctext&gt;
		&lt;/common_name&gt;
	&lt;/template&gt;

&lt;/service&gt;
&lt;/service_bundle&gt;</pre>
<p>And the very short script it calls to start Solr:</p>
<p>svc-solr:</p>
<pre class="shell">#!/bin/sh                                                                                 

nohup java -Dsolr.data.dir=/opt/local/share/solr/data -jar start.jar &amp;</pre>
<p>That&#8217;s about it.</p>
<img src="http://feeds.feedburner.com/~r/phatness/~4/kr1VWCo9HNo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/02/smf-solr/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/02/smf-solr/</feedburner:origLink></item>
		<item>
		<title>Troubleshooting SMF Service Startup</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/ywzQjf8Gt7Q/</link>
		<comments>http://phatness.com/2010/01/troubleshooting-smf-service-startup/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 20:18:46 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[System Admin]]></category>
		<category><![CDATA[Linux To Solaris]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2059</guid>
		<description><![CDATA[As I was working on my SMF scripts for the migration from Linux, I found some fancy ways to trace what was happening with a service that failed to start with new configuration.
There is a command called truss which allows you to follow along as something is being executed.  See: man truss.
What I found [...]]]></description>
			<content:encoded><![CDATA[<p>As I was working on my SMF scripts for the migration from Linux, I found some fancy ways to trace what was happening with a service that failed to start with new configuration.</p>
<p>There is a command called truss which allows you to follow along as something is being executed.  See: man truss.</p>
<p>What I found really cool is that you can modify your existing SMF script from the command line.  No need to make changes to xml and then reimport.</p>
<p>So back to the tip, if a service isn&#8217;t starting and you have eliminated all of the other possibilities with configuration, you need to see what the service script is doing.  In my case, I was having a hell of a time with Red5.  So here is what you can do:<br />
<span id="more-2059"></span><br />
Use to find what is the start method.  In this case, /opt/local/share/red5/red5.sh:</p>
<pre class="shell">[user@host ~]$ svcprop -p start/exec red5</pre>
<p>Install a new start method:</p>
<pre class="shell">[user@host ~]$ svccfg -s red5 setprop 'start/exec = “truss -f -a -o /tmp/truss.out red5.sh”'</pre>
<p>Now try to start the service again:</p>
<pre class="shell">[user@host ~]$ svcadm clear red5
[user@host ~]$ svcadm enable red5</pre>
<p>Notice the clear command!  That tripped me up several times when you would enable the service, but no warning was thrown about it being in maintenance mode.</p>
<p>Now go check the contents of /tmp truss.out to see what happened.  My problem for red5 is that I was using a relative path to red5.sh.  I specified in the environment that the working directory was /opt/local/share/red5.  However, it appears that you still must specify an absolute path to the script.</p>
<img src="http://feeds.feedburner.com/~r/phatness/~4/ywzQjf8Gt7Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/01/troubleshooting-smf-service-startup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/01/troubleshooting-smf-service-startup/</feedburner:origLink></item>
		<item>
		<title>SMF: Red5</title>
		<link>http://feedproxy.google.com/~r/phatness/~3/7vHFHOPuEvA/</link>
		<comments>http://phatness.com/2010/01/smf-red5/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 15:26:25 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[System Admin]]></category>
		<category><![CDATA[Linux To Solaris]]></category>

		<guid isPermaLink="false">http://phatness.com/?p=2046</guid>
		<description><![CDATA[Red5 is the open source answer to Adobe&#8217;s Flash Streaming Server.  I use it not for streaming, but for recording audio and video from a user&#8217;s web browser.  Yeah, that is a really cool feature if you have the need for it.
It turns out that the Red5 team actually created an SMF configuration. [...]]]></description>
			<content:encoded><![CDATA[<p>Red5 is the open source answer to Adobe&#8217;s Flash Streaming Server.  I use it not for streaming, but for recording audio and video from a user&#8217;s web browser.  Yeah, that is a really cool feature if you have the need for it.</p>
<p>It turns out that the Red5 team actually created an SMF configuration.  However, you have to download the source to get to it.  I was half way through my own before I saw the change entry on the Red5 commit mailing list.  However, it used some funky paths.  I took this and fixed it for my Joyent specific installation.<br />
<span id="more-2046"></span><br />
First, download the tar of red5 from red5.org.  Extract the contents to /opt/local/share/red5-VERSION.  Create a symlink from /opt/local/share/red5 to red5-VERSION.</p>
<p>Here is the SMF config:</p>
<pre class="html">
&lt;?xml version=&#x27;1.0&#x27;?&gt;
&lt;!DOCTYPE service_bundle SYSTEM
&#x27;/usr/share/lib/xml/dtd/service_bundle.dtd.1&#x27;&gt;
&lt;!--
Solaris Service Management Facility for Red5

The idea for this file came from a post by Paul Oswald
URL: http://pauloswald.com/article/29/hudson-solaris-smf-manifest
Modified for use with Red5 by Paul Gregoire (mondain@gmail.com)
Modified for Red5 on Joyent accelerators by The Dude

More info: 

http://www.sun.com/bigadmin/content/selfheal/smf-quickstart.jsp

http://www.sun.com/bigadmin/content/selfheal/sdev_intro.html

--&gt;
&lt;service_bundle type=&quot;manifest&quot; name=&quot;Red5&quot;&gt;

&lt;service
	name=&quot;application/red5&quot;
	type=&quot;service&quot;
	version=&quot;1&quot;&gt;

	&lt;create_default_instance enabled=&quot;false&quot; /&gt;
	&lt;single_instance /&gt;

	&lt;dependency name=&#x27;fs&#x27;
		grouping=&#x27;require_all&#x27;
		restart_on=&#x27;none&#x27;
		type=&#x27;service&#x27;&gt;
		&lt;service_fmri
			value=&#x27;svc:/system/filesystem/local&#x27;/&gt;
    &lt;/dependency&gt;

    &lt;dependency name=&#x27;net&#x27;
		grouping=&#x27;require_all&#x27;
		restart_on=&#x27;none&#x27;
		type=&#x27;service&#x27;&gt;
		&lt;service_fmri value=&#x27;svc:/network/loopback&#x27;/&gt;
    &lt;/dependency&gt;

    &lt;dependent name=&#x27;solr_multi-user&#x27;
 		grouping=&#x27;optional_all&#x27;
		restart_on=&#x27;none&#x27;&gt;
		&lt;service_fmri value=&#x27;svc:/milestone/multi-user&#x27;/&gt;
    &lt;/dependent&gt;

	&lt;method_context working_directory=&#x27;/opt/local/share/red5&#x27;&gt;
		&lt;method_credential user=&#x27;red5&#x27; group=&#x27;red5&#x27; /&gt;
	&lt;/method_context&gt;

	&lt;exec_method
		type=&quot;method&quot;
		name=&quot;start&quot;
	    exec=&quot;/opt/local/share/red5/red5.sh&quot;
	    timeout_seconds=&quot;0&quot;&gt;
	&lt;/exec_method&gt;

	&lt;exec_method
		type=&quot;method&quot;
		name=&quot;stop&quot;
	    exec=&quot;:kill -TERM&quot;
	    timeout_seconds=&quot;30&quot;/&gt;

	&lt;!-- Red5 runs as a single child process so we want Wait mode--&gt;
	&lt;property_group name=&#x27;startd&#x27; type=&#x27;framework&#x27;&gt;
		&lt;propval name=&#x27;duration&#x27; type=&#x27;astring&#x27; value=&#x27;child&#x27; /&gt;
	&lt;/property_group&gt;

	&lt;stability value=&quot;Unstable&quot; /&gt;

	&lt;template&gt;
		&lt;common_name&gt;
			&lt;loctext xml:lang=&#x27;C&#x27;&gt;
				red5
			&lt;/loctext&gt;
		&lt;/common_name&gt;
		&lt;documentation&gt;
			&lt;doc_link name=&#x27;red5.org&#x27; uri=&#x27;http://red5.org/&#x27; /&gt;
		&lt;/documentation&gt;
	&lt;/template&gt;
&lt;/service&gt;
&lt;/service_bundle&gt;
</pre>
<p>This guy is a bit simpler as it doesn&#8217;t require a script to handle starting or stopping.  It assumes red5 is installed under /opt/local/share/red5.  The same applies as before for installing it:</p>
<pre class="shell">
sudo mv red5.xml /var/svc/manifest/network/
</pre>
<p>Then run the following (likely with sudo):</p>
<pre class="shell">
chown root:sys /var/svc/manifest/network/red5.xml
chmod 444 /var/svc/manifest/network/red5.xml
svccfg import /var/svc/manifest/network/red5.xml
</pre>
<p>You&#8217;ll need to have a user and group added named red5.</p>
<p>Now, time to go watch Avatar for the 5th time.  Who am I kidding?  I have to go burp Alec.</p>
<img src="http://feeds.feedburner.com/~r/phatness/~4/7vHFHOPuEvA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://phatness.com/2010/01/smf-red5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://phatness.com/2010/01/smf-red5/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 0.342 seconds. --><!-- Cached page generated by WP-Super-Cache on 2010-08-26 09:42:55 -->
