<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>FunkyNERD</title>
	<atom:link href="http://www.funkynerd.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.funkynerd.com</link>
	<description>...software and stuff</description>
	<lastBuildDate>Tue, 07 Feb 2012 02:23:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>My first OMV plugin&#8230;</title>
		<link>http://www.funkynerd.com/my-first-omv-plugin/</link>
		<comments>http://www.funkynerd.com/my-first-omv-plugin/#comments</comments>
		<pubDate>Tue, 07 Feb 2012 02:21:28 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=255</guid>
		<description><![CDATA[I&#8217;ve been using OpenMediaVault since it&#8217;s official release late last year an it&#8217;s a great network attached storage solution based on Debian Linux.  It can be extended by the use of plugins, which there are already quite a few available. I wanted to learn how to make my own plugins so I started with an [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using <a href="http://www.openmediavault.org">OpenMediaVault</a> since it&#8217;s official release late last year an it&#8217;s a great network attached storage solution based on Debian Linux.  It can be extended by the use of plugins, which there are already quite a few available.</p>
<p>I wanted to learn how to make my own plugins so I started with an APT repository proxy plugin which works with the awesome <em>apt-cacher-ng</em> tool, which is something that I wanted for myself.</p>
<p>I&#8217;m proud to announce that version 0.1.0 has just been released and is available for download from my development website.</p>
<p><a href="http://dev.funkynerd.com/projects/openmediavault-aptcacher">http://dev.funkynerd.com/projects/openmediavault-aptcacher</a></p>
<p>Sources are available and are released under the GNU/GPL3 licence.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/my-first-omv-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ECU and Wideband O2 ready to rock and roll&#8230;</title>
		<link>http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/</link>
		<comments>http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/#comments</comments>
		<pubDate>Sun, 22 Jan 2012 22:15:46 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[Car Geek]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=235</guid>
		<description><![CDATA[For the last few months I&#8217;ve been planning and working towards turbo-charging my daily driver, a 1996 Toyota RAV4.  Great car, but a bit slow and gutless, hence the upgrade. Step one is to get a tunable ECU in and running.  I have gone for a DIYAutotune Microsquirt DIYPNP module, which is actually a great [...]]]></description>
			<content:encoded><![CDATA[<p>For the last few months I&#8217;ve been planning and working towards turbo-charging my daily driver, a 1996 Toyota RAV4.  Great car, but a bit slow and gutless, hence the upgrade.</p>
<p>Step one is to get a tunable ECU in and running.  I have gone for a <a href="http://www.diyautotune.com/catalog/diypnp-nippon-denso-76pin-unassembled-kit-p-384.html">DIYAutotune Microsquirt DIYPNP</a> module, which is actually a great little unit.  Now that I&#8217;m getting close to having the ECU in and running, I need to be able to tune it, which requires monitoring the Air/Fuel ratios using a wideband O2 sensor.  My car, as standard, only has a narrowband which just isn&#8217;t good enough.  So here&#8217;s how to fit an <a href="http://www.innovatemotorsports.com/products/lc1.php">Innovative LC-1 wideband O2 sensor</a> to a 1996 Toyota RAV4.</p>
<p><span id="more-235"></span></p>
<p>The new sensor has all been calibrated and tested and working fine.  For now, I&#8217;m running one of the outputs in narrowband mode back to the stock ECU.  The second output is in wideband mode and wired up to an unused pin on the 12pin connector for the ECU.  To get the Microsquirt to use that I now just have to re-wire the O2 input to that pin.  Should be a snap.</p>
<p>This is the stock O2 sensor on the exhaust manifold with the heat shield removed.<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9516/" rel="attachment wp-att-223"><img class="size-medium wp-image-223 alignnone" title="DSC_9516" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9516-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>If you&#8217;re pulling out a stock O2 sensor, the trick is to do it while the exhaust is hot.  I now this sounds counter intuitive because you&#8217;ll probably burn yourself, it&#8217;s a must.  While the exhaust is hot, the metal is expanded and it should be easier to loosen the sensor.  While it&#8217;s cold this will be almost impossible without breaking the sensor.  Make sure you protect yourself though.  If you have high-temp gloves, use them.  I didn&#8217;t so I just wrapped an old t-shirt around my hand and was extra careful.</p>
<p>Once it&#8217;s out, should look like this:<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9517/" rel="attachment wp-att-224"><img class="alignnone size-medium wp-image-224" title="DSC_9517" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9517-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>At this point I test fitted the wideband sensor which fortunately fit into the stock bung.  This would have been a deal breaker and I&#8217;d be stuck tuning with the narrowband.  This is also why you should be careful pulling out the stock sensor because you never know when you&#8217;ll need it again, so breaking it is not cool.</p>
<p>Don&#8217;t actually fit the O2 sensor as it needs to stay out for calibration.<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9523/" rel="attachment wp-att-227"><img class="alignnone size-medium wp-image-227" title="DSC_9523" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9523-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>Next I mounted the Innovative LC-1 module.  I decided to strap it to the main wiring harness as the cable from the sensor was the perfect length to reach there.  To do this, you should probably pull the battery and battery base panel out.  That just makes it easier to get to.</p>
<p>Here&#8217;s the module strapped to the harness<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9530/" rel="attachment wp-att-229"><img class="alignnone size-medium wp-image-229" title="DSC_9530" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9530-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>Here it is from the engine side so you can see how tucked away and safe it is:<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9531/" rel="attachment wp-att-230"><img class="alignnone size-medium wp-image-230" title="DSC_9531" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9531-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>Next, feed the LC-1 main lead and serial leads through the firewall grommet and into the cabin.<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9532/" rel="attachment wp-att-231"><img class="alignnone size-medium wp-image-231" title="DSC_9532" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9532-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>&nbsp;</p>
<p>Now, on to wiring up the LC-1 module to the ECU wiring harness.  First, you need to hook up the LED and push button.  These are required for normal operation, but you&#8217;d be stupid not to add them in now while you&#8217;re at it as they are useful for calibrating and checking status.<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9537/" rel="attachment wp-att-242"><img class="alignnone size-medium wp-image-242" title="DSC_9537" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9537-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>Next, ground the system.  This is always the first thing I do and is a good rule of thumb.  If you ground things properly first, then there&#8217;s less chance of voltage trying to find another path of least resistance, like your body.  While 12v won&#8217;t do anything to a person, this is a rule I live by across the board.</p>
<p>I used the two grounds on pins 13 &amp; 26 of E4 on the ECU connector.  One is slightly thicker, so I used that for the heater ground.<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9538/" rel="attachment wp-att-240"><img class="alignnone size-medium wp-image-240" title="DSC_9538" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9538-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>Next I bridged the LC-1 output #1, which is set to narrowband mode by default, to the stock ECU O2 sensor input.<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9539/" rel="attachment wp-att-239"><img class="alignnone size-medium wp-image-239" title="DSC_9539" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9539-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>Lastly is a bit of power.  I just bridged the ECU switched 12v.  The current draw shouldn&#8217;t be enough to blow the 15A fuse on that line.<br />
<a href="http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/dsc_9540/" rel="attachment wp-att-241"><img class="alignnone size-medium wp-image-241" title="DSC_9540" src="http://www.funkynerd.com/wp-content/uploads/2012/01/DSC_9540-300x199.jpg" alt="" width="300" height="199" /></a></p>
<p>Once that&#8217;s all hooked up you can turn it on WITHOUT the sensor connected to the LC-1 module.  This forces calibration next time it&#8217;s connected.  Let the LED flash for 30 seconds.  Then turn it off, hook up the sensor and turn it back on.  The LED should flash slowly while the sensor warms up, then it will flash faster during heater calibration.  Once the LED lights steady, hold the button for 30 seconds during which the LED will be off.  Release the button and the LED will flick on for a sec, then go off while it&#8217;s calibrating.  When it&#8217;s all done the LED will light up steady and you&#8217;re good to go.</p>
<p>After this I hooked up the serial port and tested the AFRs on the stock ECU.  Currently running about 13.8 at idle which is about right.  Sweet!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/ecu-and-wideband-o2-ready-to-rock-and-roll/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Car Geek Update &#8211; ECU Works!</title>
		<link>http://www.funkynerd.com/car-geek-update-ecu-works/</link>
		<comments>http://www.funkynerd.com/car-geek-update-ecu-works/#comments</comments>
		<pubDate>Thu, 25 Aug 2011 01:36:09 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=171</guid>
		<description><![CDATA[New wideband O2 sensor, cables, hoses and stuff ups! I received my USB-Serial cable the other day and I was able to fire up and ECU and load the firmware on to it.  So far it seems to all check out and I&#8217;m getting voltage across all circuits.  I then went to plug it into [...]]]></description>
			<content:encoded><![CDATA[<p>New wideband O2 sensor, cables, hoses and stuff ups!</p>
<p><span id="more-171"></span><a href="http://www.funkynerd.com/geeking-out-my-daily-driver/ravenous/" rel="attachment wp-att-159"><img class="alignright size-medium wp-image-159" title="RAVenous" src="http://www.funkynerd.com/wp-content/uploads/2011/08/ravenous-500x333.jpg" alt="" width="300" height="199" /></a>I received my USB-Serial cable the other day and I was able to fire up and ECU and load the firmware on to it.  So far it seems to all check out and I&#8217;m getting voltage across all circuits.  I then went to plug it into the car and see if I could get some actual sensor readings (it was 9pm so I wasn&#8217;t going to try and fire it up).  First two plugs went in fine, but the third plug is wrong.  So much for &#8220;plug and play&#8221;.  Turns out it&#8217;s the usual Toyota bullshit we have to put up with where there are differences between the US and Jap-spec models.  I have a pre-crimped 12-pin plug on the way over from the US that I can splice into the factory harness to fix that though.</p>
<p>Base settings in the ECU are done and I have a pretty generic <a href="http://en.wikipedia.org/wiki/Stoichiometric">stoich</a> map set up and ready to go.  The only issues I may have is if I read the wiring diagrams wrong and the VE outputs are hooked up to the wrong pins, or my specs have the wrong injector size and my fuel flow calculations are wrong.  Fingers crossed.</p>
<p>Also, my LC-1 has arrived and will hopefully go into the car in the next week when I get time.  Picked up a second hand one off eBay for $160.  It even has the digital display.  A new LC-1 is usually $199 and with the display $349 so I think I did well considering it&#8217;s only been used once.</p>
<p>I&#8217;m planning on running the LC-1 narrowband output to the factory O2 pin on the ECU, then running the wideband output to a spare pin on my new plug.  That way I can swap between ECUs easily during the tuning period, in case I need to throw the stocker in and drive it.  I can&#8217;t really afford to have it off the road.</p>
<p>Innovative LC-1 Wideband O2 Sensor:</p>
<p><img class="alignnone" src="https://s-hphotos-ash4.fbcdn.net/325372_10150417251928642_596433641_10875384_3051019_o.jpg" alt="" width="816" height="612" /></p>
<p>Plenty of silicon vacuum hose for the new MAP sensor:</p>
<p><img class="alignnone" src="https://s-hphotos-ash4.fbcdn.net/324788_10150417251563642_596433641_10875382_7232377_o.jpg" alt="" width="816" height="612" /></p>
<p>I&#8217;m moving interstate in the next few weeks though so I&#8217;m not sure if I will do it before then.  Considering this is the first time I&#8217;ve ever tuned an ECU I can&#8217;t afford to blow up the motor before the move.  If all goes well and I have absolutely no problems getting it to start and idle ok, then I will probably finish the tune.  First sign of trouble though and it gets shelved until after the move.</p>
<p>More t/k.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/car-geek-update-ecu-works/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Geeking out my daily driver&#8230;</title>
		<link>http://www.funkynerd.com/geeking-out-my-daily-driver/</link>
		<comments>http://www.funkynerd.com/geeking-out-my-daily-driver/#comments</comments>
		<pubDate>Fri, 19 Aug 2011 04:03:01 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[Car Geek]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[car]]></category>
		<category><![CDATA[computer]]></category>
		<category><![CDATA[ecu]]></category>
		<category><![CDATA[modification]]></category>
		<category><![CDATA[rav4]]></category>
		<category><![CDATA[supra]]></category>
		<category><![CDATA[toyota]]></category>
		<category><![CDATA[turbo]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=149</guid>
		<description><![CDATA[I&#8217;m a bit of a &#8220;car person&#8221; and as such, I have two cars.  One is a hobby and is a 1998 Toyota Supra RZs with single turbo conversion and about 600hp.  My other is just my daily driver. So as it turns out, having one modified car is not enough for some people.  Once [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a bit of a &#8220;car person&#8221; and as such, I have two cars.  One is a hobby and is a 1998 Toyota Supra RZs with single turbo conversion and about 600hp.  My other is just my daily driver.</p>
<p><span id="more-149"></span>So as it turns out, having one modified car is not enough for some people.  Once you get used to power of a single turbo Supra, it&#8217;s difficult to settle for anything &#8216;normal&#8217;.  My main issue really is that I hate changing down gears when going up hills.  My daily driver is fine on flat roads but as gutless as on the hills.</p>
<p>With that in mind, I&#8217;ve decided that my poor little daily driver is getting a few &#8216;upgrades&#8217;.  So what is my daily?  It&#8217;s a 1996 Toyota RAV4 powered by a beasty naturally aspirated 2.0L 3S-FE. The car itself is immaculate inside and out and was a great find 10 months ago when I bought it.</p>
<p>Here&#8217;s what it looks like now:</p>
<p><a href="http://www.funkynerd.com/geeking-out-my-daily-driver/ravenous/" rel="attachment wp-att-159"><img class="alignnone size-medium wp-image-159" title="RAVenous" src="http://www.funkynerd.com/wp-content/uploads/2011/08/ravenous-500x333.jpg" alt="" width="500" height="333" /></a></p>
<p>The plan is to turbo-charge the motor and run about 7psi max safely.  Most people think the poor little 3S-FE will pop at 7psi, but others have done it so I&#8217;m confident it can handle it.  Things will be happening in two stages.</p>
<p><span style="color: #ff0000;"><strong>Stage 1:</strong></span> Prep the fuel system to handle boost.  This means installing a new ECU and wideband O2 sensor for tuning.<br />
<span style="color: #ff0000;"><strong>Stage 2:</strong></span> Install the turbo, manifold, fuel injectors, etc.</p>
<p><strong><span style="color: #3366ff;">The best part is, I&#8217;m hoping to do the whole lot for less than $1500. <img src='http://www.funkynerd.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </span></strong></p>
<p>Here&#8217;s what&#8217;s happening:</p>
<ul>
<li>Aftermarket MicroSquirt ECU (DIYPNP N76P)</li>
<li>Innovative LC-1 Wideband O2</li>
<li>T3 Turbo (&#8216;el Cheapo eBay job) w/ internal WG</li>
<li>T3 Exhaust Manifold</li>
<li>Custom dump</li>
<li>DENSO 320cc Fuel Injectors</li>
<li>Some random intercooler (still looking for one)</li>
</ul>
<p>So far I have the ECU built and ready to load firmware onto it.  I&#8217;m using the DIYPNP ECU from DiyAutotune.com which comes as a box of parts that you have to solder together yourself.  It took me about 4 hours to solder the mainboard and then about another two to come up with the pinouts and wire them to the board.</p>
<p>This is the state in which the ECU arrived:</p>
<p><img class="alignnone" title="ECU1" src="http://hphotos-snc7.fbcdn.net/290266_10150408365403642_596433641_10784257_6502165_o.jpg" alt="" width="816" height="612" /></p>
<p>Here it is with the mainboard all built and the controller module mounted on top:</p>
<p><img class="alignnone" title="ECU2" src="http://hphotos-ash1.fbcdn.net/286115_10150409858643642_596433641_10799332_33720_o.jpg" alt="" width="816" height="612" /></p>
<p>Wiring the Denso 76Pin PCB module to the mainboard:</p>
<p><img class="alignnone" title="ECU3" src="http://hphotos-sjc1.fbcdn.net/194644_10150409866183642_596433641_10799363_4344148_o.jpg" alt="" width="816" height="612" /></p>
<p>All done and tested with my trusty multi-meter and ready for the lid to go on:</p>
<p><img class="alignnone" title="ECU4" src="http://hphotos-sjc1.fbcdn.net/175752_10150409873903642_596433641_10799383_377869_o.jpg" alt="" width="816" height="612" /></p>
<p>The finished product.  I even bothered to put the sticker on it:</p>
<p><img class="alignnone" title="ECU5" src="http://hphotos-ash4.fbcdn.net/287498_10150409875153642_596433641_10799393_7489315_o.jpg" alt="" width="816" height="612" /></p>
<p>Pinout Wiring maps.  Yay!!:</p>
<p><img class="alignnone" title="ECU7" src="http://hphotos-ash4.fbcdn.net/285907_10150409876443642_596433641_10799396_5368723_o.jpg" alt="" width="816" height="612" /></p>
<p>The pinout wiring map probably took the longest to come up with as like any jap-spec car, documentation on wiring is a bitch to find.  I eventually found a generic 3S-FE engine repair manual in case anyone wants it (PM me).</p>
<p>Now that the ECU is built, I need to load some firmware onto it and do some internal diagnostics to make sure it detects all the circuits I have put on the mainboard (like knock sensor, 3-wire IAC, MAP sensor, etc).</p>
<p>So at this point I&#8217;m waiting for the LC-1 and some vacuum hose to arrive so that I can install the sensor and run a hose from the existing MAP sensor to the ECU.  Then it&#8217;s just a matter of plugging it in and tuning it.  Once it&#8217;s tuned, stage 1 is done and I can start collecting parts for stage 2.</p>
<p>More t/k.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/geeking-out-my-daily-driver/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pulling PhoneMinder&#8230;.</title>
		<link>http://www.funkynerd.com/pulling-phoneminder/</link>
		<comments>http://www.funkynerd.com/pulling-phoneminder/#comments</comments>
		<pubDate>Wed, 13 Jul 2011 23:34:44 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=107</guid>
		<description><![CDATA[I&#8217;ve decided to pull PhoneMinder from the Android market.  Turns out I&#8217;m the only one using it so there was no point.  If you were using it and will actually miss it (despite there being better other free options out there) then feel free to state your case here.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve decided to pull PhoneMinder from the Android market.  Turns out I&#8217;m the only one using it so there was no point.  If you were using it and will actually miss it (despite there being better other free options out there) then feel free to state your case here.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/pulling-phoneminder/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Please excuse the mess&#8230;.</title>
		<link>http://www.funkynerd.com/please-excuse-the-mess/</link>
		<comments>http://www.funkynerd.com/please-excuse-the-mess/#comments</comments>
		<pubDate>Fri, 10 Jun 2011 00:03:19 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=101</guid>
		<description><![CDATA[I&#8217;m just in the process up switching back to WordPress for running this website. Redmine is great, but for getting articles and information out on to the web, it&#8217;s a bit lacking and WordPress easily kicks it&#8217;s ass. So why not run both? Well, I am. Redmine is still accessible at http://dev.funkynerd.com and hasn&#8217;t changed. [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m just in the process up switching back to WordPress for running this website. Redmine is great, but for getting articles and information out on to the web, it&#8217;s a bit lacking and WordPress easily kicks it&#8217;s ass. So why not run both?</p>
<p><span id="more-101"></span>Well, I am. Redmine is still accessible at http://dev.funkynerd.com and hasn&#8217;t changed. In a while I will ditch the knowledgebase plug-in, but for now it will stay. All my project management will continue to be done there with no other changes.</p>
<p>In the mean time, I&#8217;m still building the theme and layout for this new website so just bare with me.  The articles I&#8217;ve got have already been moved across and I&#8217;ve got the general layout of menus and other such organisational stuff done.  Hopefully this whole process will make things a bit easier for people to find.</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/please-excuse-the-mess/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XML-RPC client class in PHP</title>
		<link>http://www.funkynerd.com/xml-rpc-client-class-in-php/</link>
		<comments>http://www.funkynerd.com/xml-rpc-client-class-in-php/#comments</comments>
		<pubDate>Thu, 09 Jun 2011 00:53:16 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=52</guid>
		<description><![CDATA[I currently have a project that requires communicating with a 3rd party application server via XML-RPC.  Having never worked with XML-RPC before  I went looking for a PHP wrapper class that could help.  Unfortunately I couldn&#8217;t find one so I had to write one from scratch.  I have decided to publish it here for anyone [...]]]></description>
			<content:encoded><![CDATA[<p>I currently have a project that requires communicating with a 3rd party application server via XML-RPC.  Having never worked with XML-RPC before  I went looking for a PHP wrapper class that could help.  Unfortunately I couldn&#8217;t find one so I had to write one from scratch.  I have decided to publish it here for anyone else that needs to use XML-RPC in PHP and wants a tidy wrapper class to make life easier.</p>
<p><span id="more-52"></span></p>
<p>This class makes use of a fantastically powerful and dangerous &#8216;magic&#8217; method named __call.   What __call does is allows any inaccessible method to be overloaded.  This means that when you instantiate the class, ANY method that is not accessible in the class will run through the __call method.  Therefore it is possible to use this class to execute methods on the remote application server.</p>
<p>Enjoy</p>
<pre>class xmlrpc_client {
	private $url;
	private $proto = 'http';
	private $host;
	private $fhost;
	private $uri = '/';
	private $port = 80;

	private $method_pfx = '';

	private $debug = false;

	function __construct($url, $method_pfx = '', $debug = false){

		$this-&gt;method_pfx = $method_pfx;
		$this-&gt;debug = $debug;

		if(preg_match('/(\w*):\/\/(.*?)(\/.*)/', $url, $matches)){
			list($this-&gt;url, $this-&gt;proto, $this-&gt;host, $this-&gt;uri) = $matches;
			switch($this-&gt;proto){
				case 'http':
					$this-&gt;port = 80;
					$this-&gt;fhost = $this-&gt;host;
					break;
				case 'https':
					$this-&gt;port = 443;
					$this-&gt;fhost = 'ssl://' . $this-&gt;host;
					break;
				default:
					$this-&gt;dbg("Unknown protocol '$this-&gt;proto'.  Defaulting to port $this-&gt;port.");
					return;
					break;
			}
			$this-&gt;dbg("Correctly parse URL '$this-&gt;url'");
		}else{
			$this-&gt;dbg("Invalid URL supplied");
			return;
		}
	}

	private function dbg($string, $op_xml = null, $force = false){
		if(!$force &amp;&amp; !$this-&gt;debug) return;
		echo "
		$string
";
		if($op_xml) echo "$op_xml";
	}

	private function notice($string, $op_xml = false){
		return $this-&gt;dbg($string, $op_xml, true);
	}

	public function __call($name, $args){

		if(!$this-&gt;fhost &amp;&amp; !$this-&gt;port &amp;&amp; !$this-&gt;uri){
			$this-&gt;dbg('No host, port or URI has been specified');
			return;
		}

		$method = ($this-&gt;method_pfx?$this-&gt;method_pfx . '.':'') . $name;
		$response = '';

		$this-&gt;dbg("Generating request for method '$method'");

		$output = array('version' =&gt; 'xmlrpc');
		$request = xmlrpc_encode_request($method, $args, $output);

		$this-&gt;dbg("opening socket to host: $this-&gt;fhost, port: $this-&gt;port, uri: $this-&gt;uri");
		$sck_fd = fsockopen($this-&gt;fhost, $this-&gt;port, $errno, $errstr, 3);

		if($sck_fd){

			$content_len = strlen($request);

			$http_request =
				"POST $this-&gt;url HTTP/1.0\r\n" .
				"User-Agent: xmlrpc-epi-php/0.2 (PHP)\r\n" .
				"Host: $this-&gt;host\r\n" .
				"Content-Type: text/xml\r\n" .
				"Content-Length: $content_len\r\n" .
				"\r\n" . $request;

			$this-&gt;dbg("Sending HTTP request:", $http_request);

			fputs($sck_fd, $http_request, strlen($http_request));

			$this-&gt;dbg('Receiving response');

			$header_parsed = false;

			$line = fgets($sck_fd, 4096);
			while ($line) {
				if(!$header_parsed){
					if($line === "\r\n" || $line === "\n"){
						$this-&gt;dbg('Got header:', $header);
						$header_parsed = 1;
					}else{
						$header .= $line;
					}
				}else{
					$response_buf .= $line;
				}
				$line = fgets($sck_fd, 4096);
			}

			fclose($sck_fd);

			$this-&gt;dbg('Reponse:', $response_buf);

			$response = xmlrpc_decode($response_buf);

			if((is_array($response)?xmlrpc_is_fault($response):false)){
				$this-&gt;notice("Error #$response[faultCode] - $response[faultString]");
				$response = null;
			}

		}else{

			$this-&gt;dbg("Unable to open socket.  ERR: $errno# - $errstr");
		}

		return $response;
	}

}</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/xml-rpc-client-class-in-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Creating a Git repository and making it public</title>
		<link>http://www.funkynerd.com/creating-a-git-repository-and-making-it-public/</link>
		<comments>http://www.funkynerd.com/creating-a-git-repository-and-making-it-public/#comments</comments>
		<pubDate>Thu, 09 Jun 2011 00:46:17 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=49</guid>
		<description><![CDATA[The standard Git documentation is pretty damn good, but a bit long-winded when it comes to this, so I thought I would create a more succinct HOWTO here. Our Goal Or goal is simple.  We have some code that we&#8217;ve written and we&#8217;d like to turn it into a Git repository that is stored on [...]]]></description>
			<content:encoded><![CDATA[<p>The standard Git documentation is pretty damn good, but a bit long-winded when it comes to this, so I thought I would create a more succinct HOWTO here.</p>
<p><span id="more-49"></span></p>
<p><strong>Our Goal</strong></p>
<p>Or goal is simple.  We have some code that we&#8217;ve written and we&#8217;d like to turn it into a Git repository that is stored on our Git server.  In this example I will be using the procedure I used to add Snippy:http://dev.funkynerd.com/projects/snippy to my public Git server.</p>
<p><strong>Housekeeping</strong></p>
<p>Before we do anything here, there are a few things you may need to get setup first.  You only need to do these once so if you have already done them you can just skip this section</p>
<p><strong>User-based Git Config</strong></p>
<p>It is ALWAYS a good idea to have a .gitconfig file in your home directory (for Linux workstations, obviously).  So, create the file <em>~/.gitconfig</em> and add at least the following to it.</p>
<pre>[user]
name = {your name}
email = you@yourdomain.com</pre>
<p>This is used by Git when you commit stuff and makes sure that your commit identity is consistent.  May I also suggest that you do this for everything computer that you expect to commit to git from, regardless of platfrom, and make sure the parameters are consistant.  This will save on some ugliness later.</p>
<p>If you are on Windows, then sorry, I can&#8217;t help you right now, but I&#8217;m sure you can figure it out.</p>
<p><strong>Create the repository root directory</strong></p>
<p>I keep all my code repositories in <em>/var/local/git</em>.  Here is a listing of how it looks:</p>
<pre>drwxr-sr-x 7 root staff 4096 2011-02-01 11:41 git</pre>
<p>As you can see, I have added the directory to the _staff_ group and make the group sticky.  This means that anything created under that directory will have the default group of <em>staff</em>.  Make sure your Git repository directory is setup like this.</p>
<p>To get the directory created just do the following:</p>
<pre>$ sudo mkdir /var/local/git
$ sudo chgrp staff /var/local/git
$ sudo chmod g+ws /var/local/git</pre>
<p>That&#8217;s all there is to it.  Now we have a nice place to start adding our repositories.</p>
<p><strong>Initialise the local repository</strong></p>
<p>Basically all we need to do is change to the directory where our code is, create an empty Git repository and make our initial commit.</p>
<pre>$ cd /usr/src/snippy
$ git init
Initialized empty Git repository in /usr/src/snippy/.git/
$ git add *
$ git commit</pre>
<p>When prompted, add your initial commit message (I usually just put &#8220;Initial commit of {project name}&#8221;).  You now have a populated local repository that you can use &#8220;as is&#8221; to manage your code.  Even if you choose not to make it public now, you can do so later at any time by just continuing on with the below steps.</p>
<p><strong>Create a public repository</strong></p>
<p>This bit is the most complicated part due to the permissions required to allow write access to certain users.  Hopefully the steps below make it a bit easier to follow.</p>
<p>Here&#8217;s how you create the repository and set the permissions up to allow write access.</p>
<pre>$ sudo git init --bare /var/local/git/snippy.git
Initialized empty Git repository in /var/local/git/snippy.git/
$ sudo chmod -R g+w /var/local/git/snippy.git
$ sudo touch /var/local/git/snippy.git/git-daemon-export-ok</pre>
<p><strong>Note:</strong> The <em>git-daemon-export-ok</em> is required to allow the git-daemon to export the repository.  If this file does not exist, the git-daemon will not export it.</p>
<p>That&#8217;s it.  Now you just need to make sure that anyone you want to allow access to write to your repository is a member of the <em>staff</em> group.</p>
<p><strong>Making our repository public</strong></p>
<p>This step involves setting up our local repository with the location of our previously created public repository and pushing our commit out to it.</p>
<p><strong>Setting up</strong></p>
<p>When we initialised the local repository, Git created a hidden sub-directory called <em>.git</em>.  In there is a file called <em>config</em> that we need to edit.</p>
<p>Mine looks like this:</p>
<pre>[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = git://dev.funkynerd.com/snippy.git
[branch "master"]
remote = origin
merge = refs/heads/master
[remote "pub"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = ssh://dev.funkynerd.com/var/local/git/snippy.git
push = refs/heads/master:refs/heads/master</pre>
<p>The <em>[remote "origin"]</em> section defines a remote repository that we can fetch from.  The <em>[branch "master"]</em> section tells git that master is a remote branch located on the *origin* server which is where we want to get our sourcecode from when we issue a *pull* command with no repository specified.  Finally, <em>[remote "pub"]</em> defines a remote repository that we can write to for push commands.  Notice that this uses <em>ssh</em> instead of <em>git</em>.  This is because <em>git</em> does not allow writing.  This is also so that git can make use of ssh&#8217;s security functions.  So if you can <a href="http://www.funkynerd.com/setting-up-public-key-authentication-over-ssh/">ssh to the server with a shared key</a>, then you can push your git repository.  If you don&#8217;t use a shared key then you can still use a password if your ssh server allows it.</p>
<p><strong>Making the push</strong></p>
<p>Lastly, all we need to do is push our local repository to the public one.</p>
<pre>$ git pull
$ git push pub
Counting objects: 160, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (152/152), done.
Writing objects: 100% (160/160), 293.01 KiB, done.
Total 160 (delta 26), reused 0 (delta 0)
To ssh://dev.funkynerd.com/var/local/git/snippy.git
* [new branch]      master -&gt; master</pre>
<p>If you see something like the above then you&#8217;re good to go.  For good measure it always recommended that you issue a <em>git pull</em> once you&#8217;ve done a push, just to make sure everything is in sync.</p>
<p>This time, you should get the following:</p>
<pre>$ git pull
Already up-to-date.</pre>
<p>You&#8217;re now good to go.</p>
<p><strong>On-going usage</strong></p>
<p>While you continue to develop just be aware that there may be others pushing changes to the public repository.  Git is pretty good at getting the right changes in without messing up things but there are some good practices to keep in mind that help minimise the chance of something getting screwed up.</p>
<p><strong>Before you push, do a pull.</strong></p>
<pre>$git add
$git commit
$ git pull
Already up-to-date.
$ git push pub</pre>
<p>You may not always be up to date and some changed may come down.  Most of the time they will just get merged in without a problem.  Sometimes there will be conflicts which Git will guide you through resolving at this point.</p>
<p><strong>When you&#8217;ve pushed, do another pull</strong></p>
<pre>$ git push
$ git pull
Already up-to-date.</pre>
<p>This just keeps everything in sync.  See, when you push stuff to the remote repository that push is also tracked as a commit and has a commit ID.  It&#8217;s wise to do a pull straight away so that those commits are also known in your local respository.  Really, it would be nice if a push implied a pull because 99.9% of the time you do this.  But the coolness of Git is that it caters for all situation, including the 0.01% of the time you don&#8217;t want to pull straight away.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/creating-a-git-repository-and-making-it-public/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting Redmine, Git and Gitosis working together</title>
		<link>http://www.funkynerd.com/getting-redmine-git-and-gitosis-working-together/</link>
		<comments>http://www.funkynerd.com/getting-redmine-git-and-gitosis-working-together/#comments</comments>
		<pubDate>Thu, 09 Jun 2011 00:43:22 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=46</guid>
		<description><![CDATA[I love git.  It rocks and is my &#8220;go to&#8221; for source code management.  I also love Redmine and it&#8217;s now my &#8220;go to&#8221; for project management.  They work nicely together when you don&#8217;t mind logging into your git hosting server to set up a new public repository.  Why should it?  When I can use [...]]]></description>
			<content:encoded><![CDATA[<p>I love git.  It rocks and is my &#8220;go to&#8221; for source code management.  I also love Redmine and it&#8217;s now my &#8220;go to&#8221; for project management.  They work nicely together when you don&#8217;t mind logging into your git hosting server to set up a new public repository.  Why should it?  When I can use the Redmine Gitosis plugin to do it all from the Redmine interface.  The plugin leaves a lot to be desired as far as setting it up goes, so I&#8217;m writing this article to get the changes that I needed to make out into the world.</p>
<p><span id="more-46"></span></p>
<p>This article assumes that you have a fully function installation of Redmine and know how to install plugins.  If now, the &#8220;redmine plugins&#8221;:http://www.redmine.org/projects/redmine/wiki/Plugins page is a good place to start.</p>
<p><strong>Gitosis</strong></p>
<p>The first thing we need to do is install Gitosis and get that up and running.  It can be a little tricky when you don&#8217;t know how it works and it took me a while to figure it out, so I&#8217;ll try and explain it here using my limited knowledge.</p>
<p><strong>A quick and nasty intro to Gitosis</strong></p>
<p>Gitosis is a bunch of scripts that work with a central &#8220;gitosis-admin&#8221; repository.  Users interact with git repositories as a single user and access is controlled by Gitosis.  To add repositories, you clone the gitosis-admin repo, edit the config file, and export that back to the public repo.  At this point, a post-commit hoot script is executed which &#8220;does stuff&#8221;.  This is essentially how Gitosis works.  Then you can commit to the admin repo the script runs which sets things up.  You don&#8217;t really need to know much more than that.</p>
<p><strong>Installing Gitosis</strong></p>
<p>I use Ubuntu (and so should you be) so I&#8217;m only going to go into installing it on Ubuntu here.  There is already a tonne of documentation on how to install it from the Gitosis repository on github.  Use Google.  Or if you&#8217;re lazy, just &#8220;go here&#8221;:https://github.com/res0nat0r/gitosis.</p>
<p>The steps involved are pretty much install it from APT, then initialise it with your public key.  Just two steps.  It couldn&#8217;t be easier.</p>
<p>First, you MUST create a public/private key pair that is unique to Gitosis.  You *CANNOT* use your public key as this will cause problems later down the track when you start committing things to your project repositories.  The reason I&#8217;m making a big deal about this is because it caught me out.  Most of the documentation out there for installing Gitosis refers to using your own _id_rsa_ private key file.  Don&#8217;t.  You need your own key later and it needs to be unique or this wont work.</p>
<p>I just did the following:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>$ cd /tmp
$ ssh-keygen -t rsa -f redmine_key</pre></div></div>
<p>This will create two files in _/tmp_ called *redmine_key* and *redmine_key.pub* which are your private key and public key respectively.</p>
<p>Now to install Gitosis:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>$ sudo apt-get install gitosis
$ sudo -H -u gitosis gitosis-init &lt; /tmp/redmine_key.pub</pre></div></div>
<p>In the second command, the _-H_ is absolutely necessary as the script uses the $HOME environment variable which is only set correctly with the _-H_ parameter.  When you run the gitosis-init command, you should see the following if it&#8217;s successful:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>Initialized empty Git repository in /srv/gitosis/repositories/gitosis-admin.git/
Reinitialized existing Git repository in /srv/gitosis/repositories/gitosis-admin.git/</pre></div></div>
<p>At this point, Gitosis is installed and ready to go.  But, to make sure you are going to test it, right?  Let&#8217;s do that.</p>
<p>Normally at this point you would create a test project to test the gitosis install but seeing as we are using a separate unique private key, we can&#8217;t.  Trust me though.  If you&#8217;ve gotten this far without error, it will work.</p>
<p><strong>Install the Gitosis Redmine plugin</strong></p>
<p>Up until now, you&#8217;ve been doing stuff that is pretty easy and common to all Gitosis installs.  The next part takes some work because the plugin itself while good when it&#8217;s working, *WILL NOT* work out of the box.  That is, you need to make a few changes to get it working AT ALL.  A lot of the changes are to fix silly bugs that the author has not bothered to fix as yet.</p>
<p>So, here we go.</p>
<p><strong>Install</strong></p>
<p>This part is common to all Redmine plugins, and this one is no different.  You _should_ know how to do this.  Just remember to replace _/usr/share/redmine_ with wherever your version of Redmine is installed.</p>
<p>As your redmine user, do the following to install the plugin:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>$ cd /usr/share/redmine
$ script/plugin install git://github.com/rocket-rentals/redmine-gitosis.git
$ cd vendor/plugins
$ mv redmine-gitosis redmine_gitosis</pre></div></div>
<p>Now we need to fix up the database definition and a tiny little bit of code to make it all work correctly.  See, the problem is that the code refers to a field in the database as an integer, but in the database it&#8217;s a boolean.  This is wrong and wont work.  So we need to update the database definition to create the field as an integer instead, then fix the one place that it actually does refer to it as a boolean.  Blah.  What a pain.</p>
<p><strong>Fix the plugin</strong></p>
<p>From the plugins directory (you should be in it), edit _redmine_gitosis/db/migrate/20091119162427_create_gitosis_public_keys.rb_ (the number _may_ be different, but you&#8217;ll find it) and change this:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>t.column :active, :boolean, :default =&gt; true</pre></div></div>
<p>to this:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>t.column :active, :integer, :default =&gt; 1</pre></div></div>
<p>It should be about the 7th line down and quite easy to find.</p>
<p>Now, edit _redmine_gitosis/app/helpers/gitosis_public_keys_helper.rb_ and change the only two lines with true and false in the from this:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>["#{l(:status_active)} (#{key_count_by_active[true].to_i})", GitosisPublicKey::STATUS_ACTIVE],
["#{l(:status_locked)} (#{key_count_by_active[false].to_i})", GitosisPublicKey::STATUS_LOCKED]], selected)</pre></div></div>
<p>to this:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>["#{l(:status_active)} (#{key_count_by_active[1].to_i})", GitosisPublicKey::STATUS_ACTIVE],
["#{l(:status_locked)} (#{key_count_by_active[0].to_i})", GitosisPublicKey::STATUS_LOCKED]], selected)</pre></div></div><br />
Basically we are removing the true/false references and replacing them with 1/0 respectively.</p>
<p><strong>Migrate (create the database stuff)</strong></p>
<p>Now we can migrate the plugin as normal:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>$ rake db:migrate:plugins RAILS_ENV=production</pre></div></div>
<p><strong>Configure the plugin</strong></p>
<p>Before we can start using the plugin, we need to make sure it knows how to talk to Gitosis.  The defaults will most likely NOT work.</p>
<p>This is the setup for Ubuntu.  But if you&#8217;re not on Ubuntu you should know what to replace by now.  Just edit _redmine_gitosis/lib/gitosis.rb_ and set:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre># server config
GITOSIS_URI = 'gitosis@www.funkynerd.com:gitosis-admin.git'
GITOSIS_BASE_PATH = '/srv/gitosis/repositories/'</pre></div></div>
<p>The last thing we need to do is add the private key for Gitosis to the plugin.  We created this waaay back in the first step, but it should still be there.  Redmine keeps it&#8217;s private key in _{plugins_dir}/redmine_gitosis/extras/ssh/private_key_, so just do this:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>$ cp /tmp/redmine_key /usr/share/redmine/vendor/plugins/redmine_gitosis/extra/ssh/private_key</pre></div></div>
<p>Now you can restart you Redmine server.  For me that&#8217;s just:</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>$ sudo /etc/init.d/apache2 reload</pre></div></div>
<p><strong>Using the plugin</strong></p>
<p>Everything is installed and should be ready to go and the plugin should be running in Redmine.  There is one final config option we need to do for your Redmine user account.</p>
<p><strong>Add your public key to your account</strong></p>
<p>From the Redmine interface, click on &#8220;My Account&#8221; to access your account page.  You should now see a link that says _Public Keys_, probably on the top right of the page (depends on your Redmine theme).  Click through to the Public Keys page and we can add your public key by clicking on _New Value_.</p>
<p>The page that comes up should look like this:</p>
<p><img class="alignnone" src="http://dev.funkynerd.com/attachments/16/public_key_page.png" alt="" width="480" height="258" /></p>
<p>Just give it a name and paste in the contents of your _~/.ssh/id_rsa.pub_ file.</p>
<p>Now you can add repositories to projects as you would normally.  Instead of specifying where the repo is located though, the plugin just creates it in the background.</p>
<p><strong>Committing code to the repo</strong></p>
<p>To commit your code you can do the following from your projects source dir (assuming it is not already a local git repo):</p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>$ git init
$ git remote add origin gitosis@your.servername.com:projectname.git
$ git add *
$ git push origin master</pre></div></div>
<p>Hopefully that will commit correctly and you can go back to hacking you code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/getting-redmine-git-and-gitosis-working-together/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Threading in PHP</title>
		<link>http://www.funkynerd.com/threading-in-php/</link>
		<comments>http://www.funkynerd.com/threading-in-php/#comments</comments>
		<pubDate>Thu, 09 Jun 2011 00:39:39 +0000</pubDate>
		<dc:creator>Jazz</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.funkynerd.com/?p=43</guid>
		<description><![CDATA[A while back I had a project where I needed to write a server daemon that downloaded account transactions from a bank based on a configured schedule.  This on it&#8217;s own wasn&#8217;t a very difficult task.  The thing that made this tricky was that I wanted to be able to manage it from a PHP [...]]]></description>
			<content:encoded><![CDATA[<p>A while back I had a project where I needed to write a server daemon that downloaded account transactions from a bank based on a configured schedule.  This on it&#8217;s own wasn&#8217;t a very difficult task.  The thing that made this tricky was that I wanted to be able to manage it from a PHP client interface and I had some common code that was already written in PHP that I really didn&#8217;t feel like writing again.  As you probably already know, that in order to service requests from a user interface as well monitor a execution schedule, you a pretty much screwed without being to do some threading.  This is because running things in a single thread would allow you to run the schedule OR service an interface request, but not both at the same time.</p>
<p>Therefore I decided to take it upon myself to write a PHP thread class that makes use of the PHP process control functions.</p>
<p><span id="more-43"></span></p>
<p>In the end the class turned out to be quite simple, so I can&#8217;t believe this hasn&#8217;t been done before (according to Google anyway).  It&#8217;s been a while since I wrote or used this, so if anyone has any questions feel free to post a comment and I&#8217;ll do my best to answer them.</p>
<p><strong>And without further ado, here&#8217;s the code:</strong></p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>class Thread {

    private $pref;          // Process reference
    private $pipes;         // STDIO
    private $buffer;        // Output buffer
    private $start;         // Execute start time

    private function Thread() {
        $this-&gt;pref = 0;
        $this-&gt;buffer = "";
        $this-&gt;pipes = (array)NULL;
        $this-&gt;start = time();
    }

    public static function Create( $file, $stderr = null ){

        if( ! $stderr ) $stderr = array( "pipe", "w" );

        $t = new Thread;
        $descriptor = array( 0 =&gt; array( "pipe", "r" ), 1 =&gt; array( "pipe", "w" ), 2 =&gt; $stderr );
        $t-&gt;pref = proc_open( "php -q $file ", $descriptor, $t-&gt;pipes );
        stream_set_blocking( $t-&gt;pipes[1], 0 );

        return $t;
    }

    public function isActive(){
        $this-&gt;buffer .= $this-&gt;listen();
        $f = stream_get_meta_data( $this-&gt;pipes[1] );
        return !$f["eof"];
    }

    public function Close(){
        $r = proc_close( $this-&gt;pref );
        $this-&gt;pref = NULL;
        return $r;
    }

    public function Tell( $thought ) {
        fwrite( $this-&gt;pipes[0], $thought );
    }

    public function Listen(){
        $buffer = $this-&gt;buffer;
        $this-&gt;buffer = "";
        while( $r = fgets( $this-&gt;pipes[1], 1024 ) ){
            $buffer .= $r;
        }
        return $buffer;
    }

    public function getError(){
        $buffer = "";
        while( $r = fgets( $this-&gt;pipes[2], 1024 ) ){
            $buffer .= $r;
        }
        return $buffer;
    }

    public function getStartTime(){
        return $this-&gt;start;
    }

    public function getRunTime(){
        return ( time() - $this-&gt;start );
    }
}</pre></div></div>
<p>How it works is quite simple. From your parent thread, use the Thread::Create( file.php ) method to create a new Thread object.  The code in file.php should be a whole, executable PHP program.  You can use the Thread::Tell() to send data to the threads STDIN stream and Thread::Listen() to read data from the threads STDOUT stream.  Ideally I should have written another class to handle IO inside the thread itself but my &#8216;worker thread&#8217; code uses stream_select to read strings from STDIN and then fwrite to send data back to STDOUT and the parent process.</p>
<p>This isn&#8217;t ideal, but it works quite well and has been running flawlessly in a production environment for 2 years now.</p>
<p><strong>Basic Example</strong></p>
<div class='et-box et-shadow'>
					<div class='et-box-content'><pre>$thread = Thread::Create( 'test.php' );

$thread-&gt;Tell('DOSTUFF');

while(true){
    $ret = $thread-&gt;Listen();
    if( $ret == 'DOINGSTUFF' ){
        break;
    }
}

$thread-&gt;close();</pre></div></div>
]]></content:encoded>
			<wfw:commentRss>http://www.funkynerd.com/threading-in-php/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

