<?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>don&#039;t_panic &#187; Development</title>
	<atom:link href="http://mikepultz.com/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>http://mikepultz.com</link>
	<description>personal and professional blog of mike pultz, technology specialist and serial entrepreneur.</description>
	<lastBuildDate>Tue, 01 May 2012 16:56:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>How to Make Images Look Good on the IPad 3</title>
		<link>http://mikepultz.com/2012/03/how-to-make-images-look-good-on-the-ipad-3/</link>
		<comments>http://mikepultz.com/2012/03/how-to-make-images-look-good-on-the-ipad-3/#comments</comments>
		<pubDate>Sun, 25 Mar 2012 23:23:46 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[ios]]></category>
		<category><![CDATA[ipad3]]></category>

		<guid isPermaLink="false">http://mikepultz.com/?p=872</guid>
		<description><![CDATA[The new Apple IPad (IPad 3) came out on the 16th, and probably the first thing I noticed about it is how great the screen looks. It's armed with same "retina" display that the IPhone 4 came out with a few years ago. It's great! Except for one thing- a lot of images on the web [...]]]></description>
			<content:encoded><![CDATA[<p>The new Apple IPad (<a href="http://www.apple.com/ipad/features/" target="_blank">IPad 3</a>) came out on the 16th, and probably the first thing I noticed about it is how great the screen looks. It's armed with same "retina" display that the IPhone 4 came out with a few years ago. It's great! Except for one thing- a lot of images on the web look like crap now!</p>
<p>(This first image is the standard resolution, the second is optimized for IPhone 4 and IPad 3 screens)</p>
<p><a href="http://mikepultz.com/wp-content/uploads/2012/03/cat_300.jpg"><img class="alignnone size-full wp-image-914" title="cat_300" src="http://mikepultz.com/wp-content/uploads/2012/03/cat_300.jpg" alt="" width="300" height="300" /></a>    <a href="http://mikepultz.com/wp-content/uploads/2012/03/cat_600.jpg"><img class="alignnone size-medium wp-image-915" title="cat_600" src="http://mikepultz.com/wp-content/uploads/2012/03/cat_600.jpg" alt="" width="300" height="300" /></a></p>
<p>Now- this isn't new. The IPhone 4 has the same "quirk", but I think it's less noticeable given the the size of it's screen. It really stands out on the IPad 3's 9.7 inch screen.</p>
<h3>The Problem with Pixels</h3>
<p>With the advent of high pixel density displays, the pixel itself is now a relative unit.</p>
<p>According to the <a href="http://www.w3.org/TR/CSS21/syndata.html#length-units" target="_blank">CSS 2.1 Spec</a>:</p>
<blockquote><p><em>Pixel units are relative to the resolution of the viewing device, i.e., most often a computer display. If the pixel density of the output device is very different from that of a typical computer display, the user agent should rescale pixel values.</em></p></blockquote>
<p>So, a CSS "pixel" indicates one point on the "virtual" pixel grid to which your CSS design aligns. This either directly matches the actual device, or it is "somehow" scaled to suite.</p>
<p>Talking about the new IPad 3 specifically, the new retina display has a huge 2048 x 1536 pixel resolution- double what most sites are designed for. On a desktop machine, if you doubled your screen resolution, websites would just show up half as big. But on the IPad 3, it stretches the site so it "fills up" the screen. The problem with this is stretching raster images (gif, png, jpeg's) can make them look really distorted and full of artifacts.</p>
<p>So- how do you fix this?</p>
<p>The easiest way to fix this is to make a second copy of all your images at double the resolution, and then use these versions when visitors are on an IPad or IPhone (or any device that has a higher pixel density).</p>
<h3>Fixing it in CSS</h3>
<p>The <em>min-device-pixel-ratio</em> media query can be used to target style for high pixel density displays. For the moment vendor prefixes are required, until there is a standard format. For example, Mozilla and Webkit prefixes work the same way, but Opera requires the pixel ratio as a fraction.</p>
<pre>-moz-min-device-pixel-ratio: 2
-o-min-device-pixel-ratio: 2/1
-webkit-min-device-pixel-ratio: 2
min-device-pixel-ratio: 2</pre>
<p>Right now, we only care about IPhone/IPad, so we'll use the <em>-webkit-min-device-pixel-ratio</em> tag.</p>
<p>So let's say you had a single class, loading the 300 x 300 px image:</p>
<pre>.logo {
 background-image: url(cat_300.jpg);
 width: 300px;
 height: 300px;
}</pre>
<p>You would then create a second copy of the image at 600 x 600 px resolution, and add this in your CSS:</p>
<pre>@media only screen and (-webkit-min-device-pixel-ratio: 2) {
 .logo {
   background-image: url(cat_600.jpg);
   background-size: 300px 300px;
 }
}</pre>
<p>This loads the 600 x 600 px image, but forces the background-size to 300 x 300 px when the device is a webkit device, and the pixel ratio is 2.</p>
<p>Forcing the 600 x 600 px image into a 300 x 300 px box, forces the image to a pixel density of 2.</p>
<h3>Fixing Inline Images</h3>
<p>So that's CSS- what about plain old &lt;img&gt; tags?</p>
<p>You can use the <em>window.devicePixelRatio</em> property in JavaScript to determine if the pixel density of the screen is &gt; 1 and if so, cycle through all the images on the page and change their image src to the higher resolution image.</p>
<p>An easy way to do this is to add a class to all the images you want to replace. In this case, I've added the "hd" class to the image tags.</p>
<pre>&lt;img src="cat_300.jpg" width="300" height="300" class="hd" /&gt;</pre>
<p>Then add some simple JavaScript to update the tags. In my example, I've used jQuery just to make things easier, and simply did a text replace in the src image name, changing the "300" to a 600". The width/height of the &lt;img&gt; tag needs to stay at 300 x 300 px, forcing the pixel density of 2.</p>
<pre>$(document).ready(function()
{
    if ( (window.devicePixelRatio) &amp;&amp; (window.devicePixelRatio &gt;= 2) )
    {
        var images = $('img.hd');        

        for(var i=0; i&lt;images.length; i++)
        {
            images.eq(i).attr('src', images.eq(i).attr('src').replace('300', '600'))
        }
    }
});</pre>
<p>Now, there are all sorts of ways to do this- this is just one example.</p>
<p>The other way to do this is to just always load the higher resolution images. The only downside, is those higher resolution images are likely almost twice the size of their originals- so loading them only when required will save bandwidth.</p>
<h3>What about SVG?</h3>
<p>SVG (<a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics" target="_blank">Scalable Vector Graphics</a>) is also another great way to handle this. SVG files are actually XML files that have instructions on how to "draw" the image on a canvas, rather than using a static raster image. SVG files can scale to different sizes/pixel densities, without distorting.</p>
<p>The only downsides with SVG, is that sometimes the file size for complex images are actually a lot bigger than their raster counterparts, and browser support is still incomplete- so if you care about your site working in Internet Explorer, then you still need to have some raster images and do conditional loading.</p>
<h3>Parting Thoughts</h3>
<p>Remember- you don't *actually* need to do any of this; a lot of images will still look "fine" being stretched.</p>
<p>But if you want your site to look it's best, it's worth spending the time to optimize it for higher pixel density devices- there's going to be no shortage of them in the coming years!</p>
]]></content:encoded>
			<wfw:commentRss>http://mikepultz.com/2012/03/how-to-make-images-look-good-on-the-ipad-3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Net_DNS2 Version 1.2.1</title>
		<link>http://mikepultz.com/2012/03/net_dns2-version-1-2-1/</link>
		<comments>http://mikepultz.com/2012/03/net_dns2-version-1-2-1/#comments</comments>
		<pubDate>Sun, 25 Mar 2012 02:03:39 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Net_DNS2]]></category>
		<category><![CDATA[netdns2]]></category>
		<category><![CDATA[pear]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://mikepultz.com/?p=828</guid>
		<description><![CDATA[I've released version 1.2.1 of the PEAR Net_DNS2 library- you can install it now through the command line PEAR installer: pear install Net_DNS2 Or download it directly from the Google Code page here. This is just a small maintenance release to fix a few bugs: changed the Net_DNS2_Sockets::_sock property from private to protected; this was causing [...]]]></description>
			<content:encoded><![CDATA[<p>I've released version 1.2.1 of the PEAR Net_DNS2 library- you can install it now through the command line PEAR installer:</p>
<pre>pear install Net_DNS2</pre>
<p>Or download it directly from the Google Code page <a href="https://code.google.com/p/netdns2/" target="_blank">here</a>.</p>
<p>This is just a small maintenance release to fix a few bugs:</p>
<ul>
<li>changed the Net_DNS2_Sockets::_sock property from private to protected; this was causing some problems when the request was failing.</li>
</ul>
<ul>
<li>PHP doesn't support unsigned integers, but many of the RR's return unsigned values (like SOA), so there is the possibility that the value will overrun on 32bit systems, and you'll end up with a negative value. So a new function was added to convert the negative value to a string with the correct unsigned value.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://mikepultz.com/2012/03/net_dns2-version-1-2-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Mine Twitter Streams from PHP in Real Time</title>
		<link>http://mikepultz.com/2012/01/how-to-mine-twitter-streams-from-php-in-real-time/</link>
		<comments>http://mikepultz.com/2012/01/how-to-mine-twitter-streams-from-php-in-real-time/#comments</comments>
		<pubDate>Mon, 09 Jan 2012 02:43:23 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://mikepultz.com/?p=798</guid>
		<description><![CDATA[Need to mine Twitter for tweets related to certain keywords? No problem- Twitter provides a pretty simple streaming interface to the onslaught of tweets it receives, letting you specify whatever keywords you want to search for, in a real-time "live" way. To do this, I created a simple PHP class that can run in the background, collecting [...]]]></description>
			<content:encoded><![CDATA[<p>Need to mine Twitter for tweets related to certain keywords?</p>
<p>No problem-<a href="http://mikepultz.com/wp-content/uploads/2012/01/twitter_360.jpg"><img class="alignright  wp-image-806" title="twitter_360" src="http://mikepultz.com/wp-content/uploads/2012/01/twitter_360.jpg" alt="" width="230" height="144" /></a></p>
<p>Twitter provides a pretty simple streaming interface to the onslaught of tweets it receives, letting you specify whatever keywords you want to search for, in a real-time "live" way.</p>
<p>To do this, I created a simple PHP class that can run in the background, collecting tweets for certain keywords:</p>
<p>ctwitter_stream.php</p>
<pre>class ctwitter_stream
{
    private $m_username;
    private $m_password;

    public function __construct()
    {
        //
        // set a time limit to unlimited
        //
        set_time_limit(0);
    }

    //
    // set the login details
    //
    public function login($_username, $_password)
    {
        $this-&gt;m_username = $_username;
        $this-&gt;m_password = $_password;
    }

    //
    // process a tweet object from the stream
    //
    private function process_tweet(array $_data)
    {
        print_r($_data);

        return true;
    }

    //
    // the main stream manager
    //
    public function start(array $_keywords)
    {
        while(1)
        {
            $fp = fsockopen("ssl://stream.twitter.com", 443, $errno, $errstr, 30);
            if (!$fp)
            {
                echo "ERROR: Twitter Stream Error: failed to open socket";
            } else
            {
                //
                // build the request
                //
                $request  = "GET /1/statuses/filter.json?track=";
                $request .= urlencode(implode($_keywords, ',')) . " HTTP/1.1\r\n";
                $request .= "Host: stream.twitter.com\r\n";
                $request .= "Authorization: Basic ";
                $request .= base64_encode($this-&gt;m_username . ':' . $this-&gt;m_password);
                $request .= "\r\n\r\n";

                //
                // write the request
                //
                fwrite($fp, $request);

                //
                // set it to non-blocking
                //
                stream_set_blocking($fp, 0);

                while(!feof($fp))
                {
                    $read   = array($fp);
                    $write  = null;
                    $except = null;

                    //
                    // select, waiting up to 10 minutes for a tweet; if we don't get one, then
                    // then reconnect, because it's possible something went wrong.
                    //
                    $res = stream_select($read, $write, $except, 600, 0);
                    if ( ($res == false) || ($res == 0) )
                    {
                        break;
                    }

                    //
                    // read the JSON object from the socket
                    //
                    $json = fgets($fp);
                    if ( ($json !== false) &amp;&amp; (strlen($json) &gt; 0) )
                    {
                        //
                        // decode the socket to a PHP array
                        //
                        $data = json_decode($json, true);
                        if ($data)
                        {
                            //
                            // process it
                            //
                            $this-&gt;process_tweet($data);
                        }
                    }
                }
            }

            fclose($fp);
            sleep(10);
        }

        return;
    }
};</pre>
<p>The "process_tweet()" method will be called for each matching tweet- just modify that method to process the tweet however you want (load it into a database, print it to screen, email it, etc). The keyword matching isn't perfect- if you search for a string of words, it won't necessarily match the words in that exact order, but you can check that yourself from the process_tweet() method.</p>
<p>Then create a simple PHP application to run the collector:</p>
<pre>require 'ctwitter_stream.php';

$t = new ctwitter_stream();

$t-&gt;login('your twitter username', 'your twitter password');

$t-&gt;start(array('facebook', 'fbook', 'fb'));</pre>
<p>Just provide your twitter account username/password, and then an array of keywords/strings to search for.</p>
<p>Since this application runs continuously in the background, it's obviously not meant to be run via a web request, but meant to be run from the command line of your Unix or Windows box.</p>
<p>According to the Twitter documentation, the default access level allows up to 400 keywords, so you can track all sorts of things at the same time. If you need more details about the Twitter streaming API, it's available <a href="https://dev.twitter.com/docs/streaming-api" target="_blank">here</a>.</p>
<p>This class uses the <a href="http://php.net/manual/en/wrappers.http.php" target="_blank">HTTPS PHP stream</a>- so you'll need the <a href="http://www.php.net/manual/en/book.openssl.php" target="_blank">OpenSSL extension</a> enabled for it to work.</p>
]]></content:encoded>
			<wfw:commentRss>http://mikepultz.com/2012/01/how-to-mine-twitter-streams-from-php-in-real-time/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Net_DNS2 Version 1.2.0</title>
		<link>http://mikepultz.com/2011/12/net_dns2-version-1-2-0/</link>
		<comments>http://mikepultz.com/2011/12/net_dns2-version-1-2-0/#comments</comments>
		<pubDate>Fri, 23 Dec 2011 05:27:57 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Net_DNS2]]></category>
		<category><![CDATA[netdns2]]></category>
		<category><![CDATA[pear]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://mikepultz.com/?p=779</guid>
		<description><![CDATA[I've released a new version of the PEAR Net_DNS2 library- you can install it now through the command line PEAR installer: pear install Net_DNS2 Or download it directly from the Google Code page here. This release includes a significant speed-up with the local cache by using JSON to encode the cache data, rather then the [...]]]></description>
			<content:encoded><![CDATA[<p>I've released a new version of the PEAR Net_DNS2 library- you can install it now through the command line PEAR installer:</p>
<pre>pear install Net_DNS2</pre>
<p>Or download it directly from the Google Code page <a href="https://code.google.com/p/netdns2/" target="_blank">here</a>.</p>
<p>This release includes a significant speed-up with the local cache by using JSON to encode the cache data, rather then the PHP serialize function. Using JSON loses the class information of the objects, but the data remains the same, and the serialization time is about half.</p>
<p>A Query lookup against Google DNS- NO cache</p>
<pre>time: 0.0340800285339

        Net_DNS2_RR_A Object
        (
            [address] =&gt; 199.59.148.82
            [name] =&gt; twitter.com
            [type] =&gt; A
            [class] =&gt; IN
            [ttl] =&gt; 28
            [rdlength] =&gt; 4
            [rdata] =&gt;
        )</pre>
<p>with cache + serialize</p>
<pre>time: 0.00258994102478

        Net_DNS2_RR_A Object
        (
            [address] =&gt; 199.59.148.82
            [name] =&gt; twitter.com
            [type] =&gt; A
            [class] =&gt; IN
            [ttl] =&gt; 28
            [rdlength] =&gt; 4
            [rdata] =&gt;
        )</pre>
<p>with cache + json</p>
<pre>time: 0.00178384780884

        stdClass Object
        (
            [address] =&gt; 199.59.148.82
            [name] =&gt; twitter.com
            [type] =&gt; A
            [class] =&gt; IN
            [ttl] =&gt; 28
            [rdlength] =&gt; 4
            [rdata] =&gt;
        )</pre>
<h3>Version 1.2.0</h3>
<p><strong>This version changes the way some exceptions are thrown, and may break your code!</strong></p>
<ul>
<li>added numeric error codes to the Lookups class, and had each method that throws an exception throw a numeric error code along with the message.</li>
<li>dropped all references to InvalidArgumentException; we only use the Net_DNS2_Exception from now on.</li>
<li>added the CAA, URI, TALINK, CDS and TA resource records. Some of these are experimental, but are pretty straight forward.</li>
<li>fixed a bug in formatString(); my version was only putting double quotes around strings that have spaces, but apparently ALL strings should have double quotes around them. This is how BIND does it.</li>
<li>re-organized the Net_DNS2_Lookups initialization code; it no longer creates a global object of itself.</li>
<li>fixed a bug in the caching code; in some cases it wouldn't cache the same content more then once.</li>
<li>added an option to use JSON to serialize the cache data rather than using the PHP serialize function. JSON is much faster, but loses the class definition, and becomes a stdClass object.</li>
<li>fixed a handful of cases where I was using double quotes (") where a single quote (') would be fine.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://mikepultz.com/2011/12/net_dns2-version-1-2-0/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Net_DNS2 Version 1.1.0</title>
		<link>http://mikepultz.com/2011/04/net_dns2-version-1-1-0/</link>
		<comments>http://mikepultz.com/2011/04/net_dns2-version-1-1-0/#comments</comments>
		<pubDate>Sun, 24 Apr 2011 23:40:43 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Net_DNS2]]></category>
		<category><![CDATA[dns]]></category>
		<category><![CDATA[netdns2]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://mikepultz.com/?p=603</guid>
		<description><![CDATA[Net_DNS2 version 1.1.0 is now available for download from the PEAR site, or can be installed using the "pear" command line client like: pear install Net_DNS2 This release includes support for signing DNS updates and zone transfers (AXFR's) using SIG(0), a private/public key authentication mechanism. The OpenSSL PHP extension is required for this feature to work. [...]]]></description>
			<content:encoded><![CDATA[<p>Net_DNS2 version 1.1.0 is now available for download from the <a href="http://pear.php.net/package/Net_DNS2/" target="_blank">PEAR</a> site<a href="http://pear.php.net/package/Net_DNS2/" target="_blank"></a>, or can be installed using the "pear" command line client like:</p>
<pre>pear install Net_DNS2</pre>
<p>This release includes support for signing DNS updates and zone transfers (AXFR's) using <a href="http://www.ietf.org/rfc/rfc2931.txt" target="_blank">SIG(0)</a>, a private/public key authentication mechanism. The <a href="http://ca3.php.net/manual/en/book.openssl.php" target="_blank">OpenSSL PHP extension</a> is required for this feature to work.</p>
<pre>//
// create a new Updater object
//
$u = new Net_DNS2_Updater('example.com', array('nameservers' =&gt; array('192.168.0.1')));

//
// add a SIG(0) to authenticate the request
//
$u-&gt;signSIG0('/etc/namedb/Kexample.com.+001+15765.private');

//
// send the update rquest.
//
$u-&gt;update();</pre>
<p>Support for the <a href="http://www.broadband-forum.org/ftp/pub/approved-specs/af-saa-0069.000.pdf" target="_blank">ATMA</a> resource record- a method for publishing ATM addresses via DNS.</p>
<pre>@      IN    SOA    name1.data.example.com.  name4.data.example.com. (
                                  1994041800   ; Serial  - date
                                  1800         ; Refresh - 30 minutes
                                  300          ; Retry   - 5 minutes
                                  604800       ; Expire  - 7 days
                                  3600 )       ; Minimum - 1 hour
       IN    NS     name1.data.example.com.
       IN    NS     ns.example.com.
;

salmon IN    ATMA   39.246f.000e7c9c031200010001.000012345678.00</pre>
<p>And a new simple local cache system, using shared memory (using the <a href="http://ca3.php.net/manual/en/book.shmop.php" target="_blank">PHP Shmop Extension</a>), or using a flat file.</p>
<pre>$r = new Net_DNS2_Resolver(array(

        'cache_type'    =&gt; 'shared',
        'cache_file'    =&gt; '/tmp/net_dns2.cache',
        'cache_size'    =&gt; 100000
));</pre>
<p>Caching is disabled by default, and is only used for DNS queries (and not for updates), but can drastically improve query performance.</p>
<p>For more details, see the <a href="https://code.google.com/p/netdns2/" target="_blank">Net_DNS2 Google Code</a> Page.</p>
]]></content:encoded>
			<wfw:commentRss>http://mikepultz.com/2011/04/net_dns2-version-1-1-0/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

