<?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/" version="2.0">

<channel>
	<title>Seth Call: Programmer</title>
	
	<link>http://www.sethcall.com/blog</link>
	<description>A blog by a programmer, for programmers.</description>
	<lastBuildDate>Wed, 20 Feb 2013 15:52:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/SethCallProgrammer" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="sethcallprogrammer" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Creating a ‘PUT File Server’ using only nginx</title>
		<link>http://www.sethcall.com/blog/2013/02/20/creating-a-put-file-server-using-only-nginx/</link>
		<comments>http://www.sethcall.com/blog/2013/02/20/creating-a-put-file-server-using-only-nginx/#comments</comments>
		<pubDate>Wed, 20 Feb 2013 15:52:02 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.sethcall.com/blog/?p=145</guid>
		<description><![CDATA[Here&#8217;s your problem. You need a server where you can PUT files to.  And you want to then be able to use a browser and go that same server and download files later from it. Why do you need to do this?  For any number of reasons.  Maybe you have software that needs to dump [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s your problem. You need a server where you can PUT files to.  And you want to then be able to use a browser and go that same server and download files later from it.</p>
<p>Why do you need to do this?  For any number of reasons.  Maybe you have software that needs to dump diagnostic info up somewhere central, or you are trying to automate a build process by dropping artifacts into a central repository.</p>
<p>Anyway, here&#8217;s all you need to do:</p>
<pre>server {
    listen 80;
    server_name put.domain.com;
    charset utf-8;

    location / {
	 root /var/www/dump;
	 client_body_temp_path /tmp;
	 dav_methods PUT DELETE;
	 create_full_put_path   on;
	 dav_access user:rw group:rw all:r;
	 client_max_body_size 100M;
	 autoindex on;
   }
}</pre>
<pre></pre>
<p>You could protect this by enabling HTTPS and/or authentication as additional nginx configs.</p>
<p>Anyway, once this is done, you could put a file like so:</p>
<pre>curl -T /path/to/file http://put.domain.com</pre>
<p>And open up http://put.domain.com in your browser to view what&#8217;s been put in there, and download anything of interest.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2013/02/20/creating-a-put-file-server-using-only-nginx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating a yum/apt/gem repository out of nginx</title>
		<link>http://www.sethcall.com/blog/2012/10/30/creating-a-yumaptgem-repository-out-of-nginx/</link>
		<comments>http://www.sethcall.com/blog/2012/10/30/creating-a-yumaptgem-repository-out-of-nginx/#comments</comments>
		<pubDate>Wed, 31 Oct 2012 01:18:00 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.sethcall.com/blog/?p=136</guid>
		<description><![CDATA[You can readily convert a nginx installation into a repository for yum, apt, or gems. Let&#8217;s do gems. Say you have a nginx installation. And so you have a build server churning out gems. Just do an HTTP PUT against a server configured similar to the following: server { listen localhost; client_body_temp_path /tmp; root /var/www/data/gems; [...]]]></description>
			<content:encoded><![CDATA[<p>You can readily convert a nginx installation into a repository for yum, apt, or gems.</p>
<p>Let&#8217;s do gems.</p>
<p>Say you have a nginx installation.  And so you have a build server churning out gems.  Just do an HTTP PUT against a server configured similar to the following:</p>
<p><code>server {<br />
  	listen localhost;<br />
        client_body_temp_path /tmp;<br />
        root /var/www/data/gems;<br />
	server_name gems.example.com;<br />
	dav_methods PUT DELETE;<br />
	create_full_put_path   on;<br />
	dav_access user:rw group:rw all:r;<br />
	client_max_body_size 25M;<br />
    }</code></p>
<p>This allows you to do something like:</p>
<p><code>curl -T /path/to/gem http://gems.example.com</code></p>
<p>Then, using incron, cron, or manually, rebuild your gem server&#8217;s index:<br />
<code>gem generate_index -d /var/www/html/gems </code><br />
(but this could have been yum&#8217;s createrepo or apt&#8217;s equivalent.</p>
<p>Finally, use your gem server in a gem file!</p>
<p><code>source 'http://gems.example.com'</code></p>
<p>Gist for configuring the nginx server:</p>
<p>https://gist.github.com/4108841</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2012/10/30/creating-a-yumaptgem-repository-out-of-nginx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Preparing Rails for Packaging</title>
		<link>http://www.sethcall.com/blog/2012/10/22/preparing-rails-for-packaging/</link>
		<comments>http://www.sethcall.com/blog/2012/10/22/preparing-rails-for-packaging/#comments</comments>
		<pubDate>Mon, 22 Oct 2012 18:11:13 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.sethcall.com/blog/?p=128</guid>
		<description><![CDATA[Why do this? You don&#8217;t want to have any gems or code being installed on your production Rails server from web sources, but you can ensure that are running the script below on a machine with the same architecture and distro as the target server (particularly important if you are using a gem with C [...]]]></description>
			<content:encoded><![CDATA[<h1>Why do this?</h1>
<ul>
<li>
You don&#8217;t want to have any gems or code being installed on your production Rails server from web sources, but you can ensure that are running the script below on a machine with the same architecture and distro as the target server (particularly important if you are using a gem with C extensions, such as the pg gem)</li>
<li>You want a separate package for your Rails app, separate from the assets of that Rails app</li>
</ul>
<h1>Packaging Your Rails App</h1>
<pre>bundle install # acquire all dependencies as declared in the Gemfile
bundle exec rspec # run tests--don't build a broken app, right?!
bundle package #places gems in /vendor/cache
bundle install --path vendor/bundle --local
# fake function to your 'packaging' routine.
# You could be creating a tar, deb, rpm, whatever.
# Anyway, you would package up the entire directory at a minimum.
package_app</pre>
<h1>Packaging Your Rails Assets</h1>
<pre># create asset bundles
RAILS_ENV=production  bundle exec rake assets:clean
RAILS_ENV=production bundle exec rake assets:precompile
# package up the folder public/assets and deploy to your web asset server
package_assets</pre>
<p>Hope that helps!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2012/10/22/preparing-rails-for-packaging/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Models from a Gem in Rails 3</title>
		<link>http://www.sethcall.com/blog/2012/08/06/using-models-from-a-gem-in-rails-3/</link>
		<comments>http://www.sethcall.com/blog/2012/08/06/using-models-from-a-gem-in-rails-3/#comments</comments>
		<pubDate>Tue, 07 Aug 2012 03:34:49 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.sethcall.com/blog/?p=120</guid>
		<description><![CDATA[Problem: you may want to reuse the logic in your model in multiple &#8216;downstream&#8217; applications; for instance, you may have a common user table that you want to use across all of your Rails 3 applications. If you are new to Ruby and Rails development in general, it can be a bit difficult to know [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Problem:</strong> you may want to reuse the logic in your model in multiple &#8216;downstream&#8217; applications; for instance, you may have a common user table that you want to use across all of your Rails 3 applications.</p>
<p>If you are new to Ruby and Rails development in general, it can be a bit difficult to know where Rails magic ends and standard Ruby begins.  Here is a quick check-list that one can follow in order to use a model, from another gem, in your Rails 3 application.  The following steps assume your gem is called your_gem (which means within the gem .rb files, your module name is  <strong>YourGem</strong>)</p>
<h2>In Your Rails App</h2>
<ol>
<li>Optional: In application.rb in your Rails app, before the declaration of your module, add an <span style="color: #000000">include statement to make your model names available as non-namespaced symbols.</span>
<pre>include YourGem</pre>
</li>
<li>In routes.rb of our Rails app, be sure to use <strong>scope</strong>,  if you want to use <strong>resource</strong> style routes:
<pre>scope as: "your_gem" do</pre>
<pre>    resource :some_model</pre>
<pre>end</pre>
</li>
</ol>
<h2>In Your Gem</h2>
<ol>
<li>In your gem, if you are using <strong>FactoryGirl</strong> to test your models, you will need to specify <strong>:class=&gt; &#8220;YourGem::SomeModel&#8221;</strong>, because I believe FactoryGirl needs &#8216;help&#8217; for models contained within namespaces.
<pre>FactoryGirl.define do</pre>
<pre>    factory :your_model, :class =&gt; 'YourGem::SomeModel" do</pre>
<pre>    # ...</pre>
<pre>    end</pre>
<pre>end</pre>
</li>
<li>In your gem, make sure ActiveRecord has a database connection before your tests start.  So, in spec_helper.rb, do the following:
<ol>
<li><strong>ActiveRecord::Base.establish_connection(dbconfig)</strong> # where dbconfig could be loaded from the test context of <strong>config/database.yml</strong></li>
</ol>
</li>
<li>Be sure your gem follows Rails conventions.  A gem with a name of your_gem should have a module name of <strong>YourGem</strong>.  Anything else and you may have problems with the way rails looks for models to load.</li>
</ol>
<p>In the end, I <strong>did not </strong>have to modify config.autoload_paths in my application&#8230; I certainly thought I would.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2012/08/06/using-models-from-a-gem-in-rails-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tuples in Java</title>
		<link>http://www.sethcall.com/blog/2010/12/31/tuples-in-java/</link>
		<comments>http://www.sethcall.com/blog/2010/12/31/tuples-in-java/#comments</comments>
		<pubDate>Fri, 31 Dec 2010 16:12:39 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.sethcall.com/blog/?p=113</guid>
		<description><![CDATA[I so wish there were tuples in Java. The closest thing I can think of that&#8217;s type safe and Javaish is pasted below&#8211;but also saves time typing mundane data structures. With this code, one can do: Pair pair = Tuple.createPair(&#8220;oh hai&#8221;, 12345) By the way&#8211;I hate this solution. It&#8217;s still too much tip-tapping on the [...]]]></description>
			<content:encoded><![CDATA[<p>I so wish there were tuples in Java.</p>
<p>The closest thing I can think of that&#8217;s type safe and Javaish is pasted below&#8211;but also saves time typing mundane data structures.</p>
<p>With this code, one can do:</p>
<p>Pair pair = Tuple.createPair(&#8220;oh hai&#8221;, 12345)</p>
<p>By the way&#8211;I hate this solution. It&#8217;s still too much tip-tapping on the keyboard.   </p>
<p><a href="http://msdn.microsoft.com/en-us/library/system.tuple.aspx">.NET&#8217;s Tuple is cleaner.</a> </p>
<p><code><br />
package copy.paste;</p>
<p>public class Tuple {</p>
<p>    public interface Single {</p>
<p>        ONE get1();<br />
    }</p>
<p>    public interface Pair extends Single {</p>
<p>        TWO get2();<br />
    }</p>
<p>    public interface Triple extends Pair {</p>
<p>        THREE get3();<br />
    }</p>
<p>    public interface Quad extends Triple {</p>
<p>        FOUR get4();<br />
    }</p>
<p>    public interface Quint extends Quad {</p>
<p>        FIVE get5();<br />
    }</p>
<p>    public static  Single createSingle(final ONE one) {<br />
        return new Single() {<br />
            @Override public ONE get1() {<br />
                return one;<br />
            }<br />
        };<br />
    }</p>
<p>    public static  Pair createPair(final ONE one, final TWO two) {<br />
        return new Pair() {<br />
            @Override public ONE get1() {<br />
                return one;<br />
            }</p>
<p>            @Override public TWO get2() {<br />
                return two;<br />
            }<br />
        };<br />
    }</p>
<p>    public static  Triple createTriple(final ONE one, final TWO two, final THREE three) {<br />
        return new Triple() {<br />
            @Override public ONE get1() {<br />
                return one;<br />
            }</p>
<p>            @Override public TWO get2() {<br />
                return two;<br />
            }</p>
<p>            @Override public THREE get3() {<br />
                return three;<br />
            }<br />
        };<br />
    }</p>
<p>    public static  Quad createQuad(final ONE one, final TWO two, final THREE three, final FOUR four) {<br />
        return new Quad() {<br />
            @Override public ONE get1() {<br />
                return one;<br />
            }</p>
<p>            @Override public TWO get2() {<br />
                return two;<br />
            }</p>
<p>            @Override public THREE get3() {<br />
                return three;<br />
            }</p>
<p>            @Override public FOUR get4() {<br />
                return four;<br />
            }<br />
        };<br />
    }</p>
<p>    public static  Quint createQuint(final ONE one, final TWO two, final THREE three, final FOUR four, final FIVE five) {<br />
        return new Quint() {<br />
            @Override public ONE get1() {<br />
                return one;<br />
            }</p>
<p>            @Override public TWO get2() {<br />
                return two;<br />
            }</p>
<p>            @Override public THREE get3() {<br />
                return three;<br />
            }</p>
<p>            @Override public FOUR get4() {<br />
                return four;<br />
            }</p>
<p>            @Override public FIVE get5() {<br />
                return five;<br />
            }<br />
        };<br />
    }<br />
}</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2010/12/31/tuples-in-java/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Asynchronous Processing with Camel 2.5 + JMS</title>
		<link>http://www.sethcall.com/blog/2010/10/02/asynchronous-processing-with-camel-2-5-jms/</link>
		<comments>http://www.sethcall.com/blog/2010/10/02/asynchronous-processing-with-camel-2-5-jms/#comments</comments>
		<pubDate>Sun, 03 Oct 2010 03:48:37 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Camel]]></category>

		<guid isPermaLink="false">http://www.sethcall.com/blog/?p=99</guid>
		<description><![CDATA[Camel 2.5 isn&#8217;t quite out yet, but with that release you can use the new Asynchronous Processing feature. I&#8217;ve been passing request-reply messages around with JMS for quite some time in Camel, and it&#8217;s always bothered me that threads have been tied up for the duration of the message.  Asynchronous Processing fixes that, if you [...]]]></description>
			<content:encoded><![CDATA[<p>Camel 2.5 isn&#8217;t quite out yet, but with that release you can use the new <a href="http://camel.apache.org/asynchronous-processing.html">Asynchronous Processing</a> feature.</p>
<p>I&#8217;ve been passing request-reply messages around with JMS for quite some time in Camel, and it&#8217;s always bothered me that threads have been tied up for the duration of the message.  Asynchronous Processing fixes that, if you choose to use it.</p>
<p>I don&#8217;t know what it is about Camel, though, but I have a hard time figuring out anything in terms of initially bootstrapping my routes and how that corresponds to actual Java code.  So since I got JMS + Asynchronous Processing to work, I thought I&#8217;d capture it here to help out. Here goes:</p>
<h3><strong>Route and Inline Consumer</strong></h3>
<pre>// whenever  message is sent to a.test, our AsyncProcessor defined here will fire
from("jms:queue:a.test").process(new AsyncProcessor() {
    @Override public boolean process(final Exchange ex, final AsyncCallback cb) {
           String body = ex.getIn().getBody(String.class);
           ex.getOut().setBody("Response: " + body);
           cb.done(false);
           return false;
}</pre>
<pre>@Override public void process(final Exchange exchange) throws Exception {}
});</pre>
<h3><strong>Sending message as client:</strong></h3>
<pre> // get endpoint for JMS queue defined in route above
 Endpoint endpoint = camelContext.getEndpoint("jms:queue:a.test");
 // get producer so that we can fire messages
 Producer producer = endpoint.createProducer();
 producer.start();

 // create test message
 final Exchange exchange = producer.createExchange();
 exchange.setPattern(ExchangePattern.InOut);
 DefaultMessage message = new DefaultMessage();
 message.setExchange(exchange);
 message.setBody("test");
 exchange.setIn(message);</pre>
<pre> // this cast is safe because this must be a JmsProducer
 // .process() completes immediately; AsyncCallback instance passed in has done() called
 // when the consumer above has sent it's response.</pre>
<pre> ((AsyncProcessor)producer).process(exchange, new AsyncCallback() {
      @Override public void done(final boolean b) {</pre>
<pre>          // our async callback. access original exchange for response body
          // should always check exchange.isFailed()
          System.out.println("Got response: " + exchange.getOut().getBody());
      }
 });</pre>
<p>That&#8217;s it! It&#8217;s pretty straightforward once you know what to do.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2010/10/02/asynchronous-processing-with-camel-2-5-jms/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Facebook API: A Case Study in Not Caring About Developers</title>
		<link>http://www.sethcall.com/blog/2010/09/30/facebook-api-does-not-care/</link>
		<comments>http://www.sethcall.com/blog/2010/09/30/facebook-api-does-not-care/#comments</comments>
		<pubDate>Thu, 30 Sep 2010 14:57:35 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Facebook]]></category>

		<guid isPermaLink="false">http://www.ownedthx.com/blog/?p=59</guid>
		<description><![CDATA[*UPDATE*: Carl Sjogreen, the lead of the platform PM team, commented below that positive changes are coming.  All of us should hope he and his team succeeds! Original Post: Using the Facebook API is the one of the worst experiences as a developer I have ever had.  This past week has been a real trial, [...]]]></description>
			<content:encoded><![CDATA[<p><strong>*UPDATE*</strong>: Carl Sjogreen, the lead of the platform PM team, <a href="http://www.sethcall.com/blog/2010/09/30/facebook-api-does-not-care/#comment-82465562">commented below</a> that positive changes are coming.  All of us should hope he and his team succeeds!</p>
<p><em>Original Post:</em></p>
<p>Using the Facebook API is the one of the worst experiences as a developer I have ever had.  This past week has been a real trial, and a true challenge to keep my energy and spirits up so that I remain efficient.</p>
<p>Whew, that&#8217;s off my chest.  Let me stop with the bashing, and try to digest down what they are doing wrong in an effort to try and be constructive rather than purely inflammatory.</p>
<h1>POOR DOCUMENTATION</h1>
<p>When you document your API, you have to at a minimum do the following:</p>
<ol>
<li>Define each method</li>
<li>For each method, define inputs</li>
<li>For each method, define outputs</li>
<li>Describe the possible values for every input</li>
<li>Detail possible error responses</li>
<li>Detail how configurations outside the scope of the API call may affect your code.</li>
<li>Performance limitations (rate limiting in the case of Facebook)</li>
</ol>
<p>Facebook fails to come through on <strong>all of these points,</strong> even #1</p>
<p>Example:</p>
<p>I was trying to find some part of the documentation that would describe all Facebook-created dialogs that I can use, because I wanted to show a &#8216;friend finder&#8217; equivalent to what is natively available in Facebook, but on my own website.  I find  <a href="http://developers.facebook.com/docs/reference/javascript/FB.ui">FB.ui</a> (a &#8216;Core Method&#8217;), look over the documentation for that method, which I see takes an argument called &#8230; &#8216;method&#8217;. Ok, fine, so FB.ui must actually be a class or package and not a method, but whatever.  I&#8217;m already confused a little but no biggie.</p>
<p>So once I take a look to see what&#8217;s available in <a href="http://developers.facebook.com/docs/reference/javascript/FB.ui">FB.ui</a>&#8230;there are only two methods stream.publish and stream.share! That&#8217;s not much.</p>
<p>I back up to the parent of FB.ui (&#8216;Core Methods&#8217;), click around every link I find there, do google searches, and look through the developer forum, but find no more UI-related methods.</p>
<p>I know that can&#8217;t be right. <strong>Fb.ui</strong> looks suspiciously under-documented.  I find nothing but a link to github for the Javascript SDK.  Sighing, I download the code, find the file that corresponds to FB.ui, and  see:</p>
<ul>
<li>friends.add</li>
<li>stream.publish</li>
<li>stream.share</li>
<li>fbml.dialog</li>
<li>bookmark.add</li>
<li>profile.addtab</li>
</ul>
<p>I freaking knew it.</p>
<p>How do these extra methods work? What are there limitations? It&#8217;s just javascript so even reading through the code won&#8217;t help much because it interacts with Facebook servers and therefore I can get only a partial picture at best.</p>
<p>Anyway, I then zero in on fbml.dialog, because I vaguely know FBML has a lot of predefined tags made by Facebook that I could use to make my own UI.  So I turn to the FBML documentation.  The <a href="http://developers.facebook.com/docs/reference/fbml/">main page</a> says this along the top now:</p>
<blockquote><p>Note: We do not recommend FBML for new developers. If you aren&#8217;t already using FBML, you should instead <a href="http://developers.facebook.com/docs/guides/canvas">implement your application within an <code>iframe</code></a>, using the <a href="http://developers.facebook.com/docs/reference/javascript">JavaScript SDK</a> and <a href="http://developers.facebook.com/plugins">social plugins</a> for client-side integration with Facebook services.</p></blockquote>
<p>Wait a second&#8230; I shouldn&#8217;t use FBML because I should use the Javascript SDK?  But the Javascript SDK has a method called fbml.dialog, which led me here!  So now I&#8217;m wondering if by using FBML, am I opening myself up to have the floor ripped out from under me when Facebook gets rid of FBML, because on their roadmap I see:</p>
<blockquote><p>We will stop allowing new FBML applications, but will continue to support existing FBML tabs and applications. Instead, we recommend using IFrames.</p></blockquote>
<p>But this is just a roadmap, and moreover, it&#8217;s the <a href="http://forum.developers.facebook.net/viewtopic.php?pid=265264#p265264">dubious Facebook roadmap</a>.  I decide I won&#8217;t worry about it, and try to figure out how to use fbml.dialog on my own. I know the only other option left for me is to post on the developer forums, but just the thought of doing so leaves me despondent.</p>
<p>In closing on documentation, searchability is terrible, navigation is terrible, the content is extremely thin and often wrong, and the developer forums are a wasteland of frustration.</p>
<h1>POOR TESTABILITY</h1>
<p>If I&#8217;m going to use an API, I have to test it first, right?   This is even more important with the Facebook API(s), since the documentation is so poor and the amount of issues you encounter with almost any API call ensures the only way to really know what the Facebook API will do is to simply use it.</p>
<p>Well, what if there were an API call that only worked with production code?  That&#8217;s pretty limiting, especially in the face of all the other Facebook issues.  It&#8217;s a bit chicken-and-egg to have to have production code act as your testbed, wouldn&#8217;t you say?</p>
<p>Well, unfortunately, any API call that has to do with the <strong>dashboard</strong> is subject to this limitation.</p>
<p>Side rant: what is the dashboard?  Good luck finding a generic description in the API documentation as to what it is.  You have to sift though forum posts and blog posts by Facebook to infer that the dashboard is an end-user&#8217;s left navigation.  That&#8217;s the &#8216;dashboard&#8217;.  I&#8217;d call it a left nav but hey, <strong>Dashboard</strong> sounds better, right?</p>
<p>Anyway, you can see all dashboard API methods <a href="http://developers.facebook.com/docs/reference/rest/">here</a> if you scroll down.  Oh but by the way, don&#8217;t use <a href="http://developers.facebook.com/docs/reference/rest/dashboard.publishActivity">publishActivity</a>.  From scraping the forums for hours for anything related to the dashboard, <a href="http://developers.facebook.com/docs/reference/rest/dashboard.publishActivity">I can tell you it doesn&#8217;t work</a> because other users have already been burned by using just the documentation.</p>
<p>Back to testability.  I tried out <a href="http://developers.facebook.com/docs/reference/rest/dashboard.addNews">dashboard.addNews</a>, which should make a news item show up in my stream &#8230; according to the documentation (are you starting to feel a description in the docs don&#8217;t count for a lot?). Here is the relevant description of <strong>dashboard.addNews</strong>:</p>
<blockquote><p>Calling this method appends the news items included in this call to the news stream. Facebook displays up to two news items (either personal, global, or both) at a time for a given application, starting from the two most recently added.</p></blockquote>
<p>Great! Just what I needed.  So I take the time to create a test application, create test users, and use dashboard.addNews successfully&#8211;at least, as far as the response of the API call is concerned.  But when I check the test user&#8217;s account, there is strangely no news showing for the application.  So back to the developer forums to look for similiar problems.</p>
<p>I find <a href="http://forum.developers.facebook.net/viewtopic.php?id=67910">this post</a>, which seems to imply the application must be bookmarked and submitted to the directory&#8211;or doesn&#8217;t require being in the directory depending on which user you believe in the post. Also, this <a href="http://bugs.developers.facebook.net/show_bug.cgi?id=8555">bug</a> referenced in the forums simple says that &#8216;sandboxed&#8217; applications can not be used with the dashboard, so I made sure that my application was not configured as sandboxed (which makes no sense for a test application but you do what you gotta do).</p>
<p>I found a few other forum posts talking about bookmarking, so I tried that out first when debugging. But apparently the way you bookmark applications recently changed, confusing me a while how I was supposed to do this.  Long story short is, I got my application bookmarked, and if you can imagine, addNews still didn&#8217;t work.</p>
<p>So I <a href="http://forum.developers.facebook.net/viewtopic.php?id=76301">posted on their developer forum</a>.  After 24 hours, no responses yet.  I could wait, but since most posts don&#8217;t get responses on the forums, I have to assume I won&#8217;t get one.</p>
<p>So moving on, I thought, well, I never tried submitting my application to the directory.  So I found the link for that (which is not in the configuration of the app where I spent a few minutes looking first), clicked it, and was told that I have to have at least 5 users of the application.</p>
<p>&#8230;</p>
<p>Wow.  So just to test the idea if being submitted in the directory is important, I have to somehow get 5 users associated with my application?   I had actually signed up four test users with the application, but the application reported that I only had a grand total of 0 users.</p>
<p>I eyeball another application I made for a different company, which had more than 5 users but was never published because it didn&#8217;t need to be found via the Facebook directory.  But if I could just try out dashboard.addNews with this application, maybe I&#8217;d have an answer!</p>
<p>Since I&#8217;m  <strong>luckily</strong> a co-founder of this other company, I said the heck with it, I&#8217;ll publish it.  And so I did. After 4 hours waiting for it to be approved, I then tried dashboard.addNews with this application instead of my test application.</p>
<p>Nothing happened.</p>
<p>And, this time, I can&#8217;t seem to successfully bookmark it.</p>
<p>If I make progess on this, I&#8217;ll update my developer forum post at least with my solution.</p>
<p><strong>UPDATE</strong>:  I can&#8217;t play with the <a href="http://bugs.developers.facebook.net/show_bug.cgi?id=12754">configuration of my application</a> so that I can continue debugging because of a rather major bug affecting all applications for the past 24 hours or so.</p>
<p>In closing on testability, there are other reasons that it is difficult to test Facebook applications, but I think the example here is good enough.</p>
<h1>NO RESPONSE TO SERIOUS ISSUES</h1>
<p>I&#8217;ll zero in on two.</p>
<p><strong>ORDER BY AND LIMIT in FQL</strong></p>
<p>FQL allows developers to make queries to fetch results in a SQL-like way.   A while back (I think June 2009), Facebook added ORDER BY and LIMIT to the language.  But it is horribly broken.  If you like, you can try to discern what&#8217;s wrong with ORDER BY and LIMIT by navigating through the NEW and UNCOMFIRMED bugs opened <a href="http://bugs.developers.facebook.net/buglist.cgi?quicksearch=FQL+order+by+limit">here</a>: Note that almost all bugs are NEW and UNCONFIRMED, so don&#8217;t just assume that a new bug is actually new in terms of age.</p>
<p>Please, don&#8217;t bother looking through their bug tracker.  I&#8217;ll tell you what&#8217;s wrong with ORDER BY AND LIMIT.  Basically, it seems Facebook has a sharded database backend, and simply proxies your ORDER BY and LIMIT to it&#8217;s back end data stores, meaning each sharded data store, which only has a partial set of the overall data, can&#8217;t possibly do this correctly since LIMIT will cause the sharded data store to paginate into it&#8217;s own data, limiting the data you get back artificially and incorrectly.</p>
<p>Protip: If you use ORDER BY/LIMIT, you should set the LIMIT to the max of 1000, and just get as much as you can.  Don&#8217;t ever try to paginate with FQL.</p>
<p><strong>UPDATED_ON/CREATED_ON CORRUPTED BY USING ORDER BY AND LIMIT</strong></p>
<p>I found that, for some facebook fan pages, that if I specified ORDER BY, LIMIT, then the created_on and updated_on fields returned are completely incorrect.  I <a href="http://bugs.developers.facebook.net/show_bug.cgi?id=8624">opened a bug on it</a> in February 2010, and nearly 7 months later, the state of my bug was marked as duplicate of another bug.</p>
<p>Oh boy, 7 months and I can fix my application!  Yaaaah!</p>
<p>Hold on, wait, what&#8217;s this?  The <a href="http://bugs.developers.facebook.net/show_bug.cgi?id=6436">other bug</a> is marked as unconfirmed still. Oh. It was opened in August 2009.  So it&#8217;s been over a year. I guess you just have to be patient.</p>
<p>Hey, but surely they&#8217;d warn in their documentation that ORDER BY and LIMIT are broken?</p>
<p><a href="http://developers.facebook.com/docs/reference/fql/">Not here</a>.</p>
<p><a href="http://developers.facebook.com/docs/guides/performance">Not here either</a>.</p>
<p><a href="http://developers.facebook.com/docs/reference/fql/stream">No.</a></p>
<h1>CONSTANTLY CHANGING API</h1>
<p>If you are going to constantly change your API, deprecate things, remove methods, etc, you had better be fixing major issues along the way.</p>
<p>But everything indicates that the API(s) only get more confusing and more broken, and migrations are done usually rather brutally.  You can search through the developer forum if you want to corroborate.</p>
<p>A side-effect of a constantly changing API is that you aren&#8217;t sure what you should be using versus what&#8217;s fallen out of favor.</p>
<p>Consider the the reasonably new <a href="http://developers.facebook.com/docs/reference/api/">Open Graph API</a>.  It lets you read and modify a great deal of data found within Facebook.  You could already do this with the <a href="http://developers.facebook.com/docs/reference/rest/">Old REST API</a>, but this API is easier!! and better!!</p>
<p>As a developer who has already been through the onerous task of learning the REST API, this new API was only bad news.  I don&#8217;t care to relearn, and I don&#8217;t want to rewrite existing code.  But I feel compelled to. After all, the REST API is now <em>old</em><span style="font-weight: normal">.</span></p>
<p><strong><span style="font-weight: normal">But I can&#8217;t do certain things with the shiny new Open Graph API.  For instance, the dashboard API methods in the Old REST API (I can&#8217;t get over the fact they call it OLD.  It drives me crazy every time I read it) are not in the Open Graph API.  So now, I have to use the Open Graph API if I want to be modern and in-line with Facebook, but I absolutely have to use the REST API if I want to use the dashboard (you might be laughing to yourself if you&#8217;ve noticed I&#8217;m worried about the Dashboard API when I can&#8217;t even get it to work).</span></strong></p>
<p>The removal of application notifications was a good example of this too. The dashboard API is actually a replacement for the old notification API.  I&#8217;m not sure why they couldn&#8217;t leave the old notification API in place, and just change the actual behavior, but apparently they had to build a newer and more broken API.</p>
<p>I&#8217;m <a href="http://developers.facebook.com/docs/reference/rest/">not alone</a> by the way in my frustration.</p>
<h1>Bottom Line</h1>
<p>Facebook, get it together. It&#8217;s not hard to have good documentation or good customer service, but it does require internal prioritization.  Stop not caring about developers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2010/09/30/facebook-api-does-not-care/feed/</wfw:commentRss>
		<slash:comments>103</slash:comments>
		</item>
		<item>
		<title>How to export and import an HBase table</title>
		<link>http://www.sethcall.com/blog/2010/04/10/how-to-export-and-import-an-hbase-table/</link>
		<comments>http://www.sethcall.com/blog/2010/04/10/how-to-export-and-import-an-hbase-table/#comments</comments>
		<pubDate>Sat, 10 Apr 2010 20:09:08 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Hadoop & Hbase]]></category>
		<category><![CDATA[hbase]]></category>

		<guid isPermaLink="false">http://www.ownedthx.com/blog/?p=51</guid>
		<description><![CDATA[HBase has a native export/import feature which is actually two MR jobs.  These jobs are located in the HBase codebase (contained in hbase-0.xx.x.jar under Import and Export), and so, as a normal MR job, you simple need to configure the Hadoop classpath to be aware of the jars that these MR jobs need, and then [...]]]></description>
			<content:encoded><![CDATA[<p>HBase has a native export/import feature which is actually two MR jobs.  These jobs are located in the HBase codebase (contained in hbase-0.xx.x.jar under <a href="http://hadoop.apache.org/hbase/docs/current/api/org/apache/hadoop/hbase/mapreduce/Import.html">Import</a> and <a href="http://hadoop.apache.org/hbase/docs/current/api/org/apache/hadoop/hbase/mapreduce/Export.html">Export</a>), and so, as a normal MR job, you simple need to configure the Hadoop classpath to be aware of the jars that these MR jobs need, and then run them.</p>
<p>The easiest way to alter Hadoop&#8217;s classpath is to configure hadoop-env.sh.  By default, hadoop-env.sh has a commented-out line near the top, that looks like:</p>
<pre># Extra Java CLASSPATH elements.  Optional.</pre>
<pre>#export HADOOP_CLASSPATH=</pre>
<p>Using <a href="http://hadoop.apache.org/hbase/docs/current/api/org/apache/hadoop/hbase/mapreduce/package-summary.html">this information</a>, I updated hadoop-env.sh to:</p>
<pre>export HBASE_HOME=/path/to/apache-hbase
export HADOOP_CLASSPATH=$HBASE_HOME/hbase-0.20.3.jar:$HBASE_HOME:$HBASE_HOME/lib/zookeeper-3.2.2.jar:$HBASE_HOME/conf
</pre>
<p><em>Note: once you update hadoop-env.sh, you will need to restart tasktracker and jobtracker, which is most easily done by running stop-mapred.sh then start-mapred.sh located in /path/to/apache-hadoop/bin.</em></p>
<p><em>Note: don&#8217;t try to set HBASE_HOME or HADOOP_CLASSPATH in your local terminal profile if this is the first time trying this&#8211;stick to configuring them in hadoop-env.sh.  The reason is that hadoop runs jobs by creating an SSH terminal, and depending on your system&#8217;s settings, your local terminal settings may or may not take effect in this hadoop-created SSH terminal.</em></p>
<p>Ok, now you are ready to export your table.  To see all of the export options, you can run:</p>
<pre>bin/hadoop jar /path/to/hbase-0.20.3.jar export</pre>
<pre>Usage: Export &lt;tablename&gt; &lt;outputdir&gt; [&lt;versions&gt; [&lt;starttime&gt; [&lt;endtime&gt;]]]</pre>
<p>To export the current version of the entire table, just supply tablename and outputdir.  Note that outputdir will actually export to HDFS, not your local filesystem.  In my case, the hbase cluster that I was exporting the table from had no direct IP access to my destination hbase cluster, so I had to get the files out of hdfs and into a local directory so that I could move them manually.</p>
<p>So, let&#8217;s export:</p>
<pre>bin/hadoop jar /path/to/hbase-0.20.3.jar export your_table /export/your_table</pre>
<p>Our hbase table is in HDFS under /export/your_table. Let&#8217;s get the entire table into your local filesystem (hopefully your hbase table isn&#8217;t huge!), by running:</p>
<pre>bin/hadoop -copyToLocal /export/your_table /somewhere/local</pre>
<p>I then scp -r /somewhere/local to my local dev station (where my other hbase &#8216;cluster&#8217; is).  With the file on my dev system after the copy, we need to get the file back into HDFS, and then run the import MR job.</p>
<p>Copy from your system&#8217;s harddrive to HDFS:</p>
<pre>bin/hadoop -copyFromLocal /somewhere/local /import/your_table</pre>
<pre>bin/hadoop jar /path/to/hbase-0.20.3.jar import your_table  /import/your_table</pre>
<p><em>Note: If you were copying large amounts of data between clusters, SCP copying probably isn&#8217;t a real good solution.   Hadoop has a feature called distcp, which can be used to leverage the power of the two clusters to copy large amounts of data.  You can read more about that <a href="http://hadoop.apache.org/common/docs/current/distcp.html">here</a>.</em></p>
<p>Finally, I want to give a huge amount of thanks to <a href="http://jdcryans.blogspot.com/">jdcryans</a>, who literally bootstrapped me through the entire process.  Without him and his constant help in IRC, I don&#8217;t know what I&#8217;d do (and many others, I&#8217;m sure).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2010/04/10/how-to-export-and-import-an-hbase-table/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>OAuth is a pain to use for desktop applications</title>
		<link>http://www.sethcall.com/blog/2009/05/10/oauth-is-a-pain-to-use-for-desktop-applications/</link>
		<comments>http://www.sethcall.com/blog/2009/05/10/oauth-is-a-pain-to-use-for-desktop-applications/#comments</comments>
		<pubDate>Sun, 10 May 2009 18:18:01 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[OAuth]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://www.ownedthx.com/blog/?p=47</guid>
		<description><![CDATA[OAuth (used by the likes of Twitter and others) is a protocol designed to negate the need for users to give 3rd-parties their username &#38; password. A laudable goal! However, using it can be a real pain when building a desktop application.  It&#8217;s easiest to describe the problem with an example. Say you want to [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://oauth.net/">OAuth</a> (used by the likes of Twitter and others) is a protocol designed to negate the need for users to give 3rd-parties their username &amp; password. A laudable goal!</p>
<p>However, using it can be a real pain when building a desktop application.  It&#8217;s easiest to describe the problem with an example.</p>
<p>Say you want to build a desktop application that integrates with Twitter.  To do so, you have to signup for an API account at Twitter (true for any OAuth service provider), and obtain a secret key which you must ensure never falls into the hands of anyone but you and your application.  The reason this key must stay secret is that it is used to create a hash (OAuth refers to it as signing)  of every API message sent from your application to the OAuth service provider; lose the key, and anyone can impersonate your application.</p>
<p>So the secret key must stay secret.  And what do you, the hapless  developer, do?  You put it on a server, because it&#8217;s the only place you can ensure that it stays safe.  So, now, for your desktop application to do anything with the API, it has to send messages up to your server to have the API message signed.</p>
<p>Now here&#8217;s the real sticking point.  You have to know the identity of the user before signing the request coming to your server.  And how do you know that?  The user has to somehow log in to this server you were using previously just to perform signing.</p>
<p>Great. Now the user has to create a username &amp; password to your site, just so you can use OAuth with Twitter.</p>
<p>So, in the end, you users still have to get involved with a username &amp; password.  Sure, your Twitter username &amp; password stays locked in Twitter&#8230; which is good, no question. But the user experience is still cumbersome, and the amount of work the developer to do is quite high, especially in the case that you don&#8217;t already have a web site and login process.</p>
<p>So, in summary, to make a desktop application secure with OAuth, <em>you are forced to make a website with a login if you don&#8217;t already have one</em>.  Ouch.</p>
<p>I&#8217;m admittedly new to OAuth but as far as I can tell, this is the state of affairs with OAuth and desktop applications.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2009/05/10/oauth-is-a-pain-to-use-for-desktop-applications/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Flash completely dominates CSS/HTML/JS for rendering text accurately</title>
		<link>http://www.sethcall.com/blog/2009/04/27/flash-completely-dominates-csshtmljs-for-rendering-text-accurately/</link>
		<comments>http://www.sethcall.com/blog/2009/04/27/flash-completely-dominates-csshtmljs-for-rendering-text-accurately/#comments</comments>
		<pubDate>Mon, 27 Apr 2009 23:09:45 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Flash Flex CSS JS HTML font word]]></category>

		<guid isPermaLink="false">http://www.ownedthx.com/blog/?p=11</guid>
		<description><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_animation_1931728906"
			class="flashmovie"
			width="676"
			height="372">
	<param name="movie" value="http://www.ownedthx.com/media/animation.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="http://www.ownedthx.com/media/animation.swf"
			name="fm_animation_1931728906"
			width="676"
			height="372">
	<!--<![endif]-->
		 
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object> EDIT!  The SWF above is just an animation I made of two screenshots; one of Word, one of Flash text engine results.  It is 100% to make the text selectable, but this particular animation does not showcase that. A Flash generated bit of text overlaid on top of Microsoft [...]]]></description>
			<content:encoded><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_animation_671855800"
			class="flashmovie"
			width="676"
			height="372">
	<param name="movie" value="http://www.ownedthx.com/media/animation.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="http://www.ownedthx.com/media/animation.swf"
			name="fm_animation_671855800"
			width="676"
			height="372">
	<!--<![endif]-->
		
<p><a href="http://adobe.com/go/getflashplayer"><img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" /></a></p>

	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object>
<p><em><strong>EDIT!  The SWF above is just an animation I made of two screenshots; one of Word, one of Flash text engine results.  It is 100% to make the text selectable, but this particular animation does not showcase that.</strong></em></p>
<p><em>A Flash generated bit of text overlaid on top of Microsoft Word.  Every word of the paragraph matches pixel-perfect.  It&#8217;s actually rather hard to notice&#8211;when the red squiggly lines disappear, that&#8217;s when you are looking at the flash text.  When they reappear, that&#8217;s when you are looking at Word text.</em></p>
<p> </p>
<p>I never thought this day would come, but go ahead and consider me a convert&#8230; </p>
<p>The new <strong>flash.text.engine</strong> namespace within Flash 10 is the typographically correct way to render text for the web.  Anyone who has attempted to render a simple paragraph across multiple browsers quickly realizes how little control we as developers have over the rendering of text on the web.  Just take a look at <a title="Font Rendering Differences: Firefox vs. IE vs. Safari" href="http://css-tricks.com/font-rendering-differences-firefox-vs-ie-vs-safari/">Font Rendering Differences: Firefox vs. IE vs. Safari</a> if this problem doesn&#8217;t resonate with you.</p>
<p>With <strong>flash.text.engine</strong>, persistent problems such as lack of support for custom fonts and kerning go away entirely. Pixel-perfect rending across browsers is achievable&#8211;the only question left is whether flash is acceptable to you and your Web 2.0 philosophies.</p>
<p>If you are still with me, then let&#8217;s explore <strong>flash.text.engine</strong> a little more deeply&#8230;</p>
<p>Because the new Flash text engine provides such accurate text rendering, a web application can now exert minute control over the layout of text, therefore having the capability to render formats that assume access to print-quality text rendering.  For example, say we wanted to render an uploaded Microsoft Word file in a web page, with faithful reproduction of the  pagination and positioning of every element in the document, as rendered by the Word application itself.  If one were to inspect a Microsoft Word document, they would see that it contains information about font size, family, page margins, and the actual text contained in the document, but does not explicitly indicate on which page any element within the document falls (such as paragraphs, tables, and images).   Word instead figures out pagination as it loads and renders a given document .  So, your web application would have to be able to mimic the Word rendering engine to pull this off!  Good luck trying to do that with only HTML, CSS, and Javascript.  (to be fair, good luck trying that with any technology, but we are going to try our luck with Flex for the sake of this article).</p>
<p>Let&#8217;s back up a second and look at basic usage of the Flash text engine.  At the heart of the text engine is the TextBlock  class.  It makes rendering paragraphs of a set width very straightforward.</p>
<p>To use it, set up the <strong>TextBlock</strong> with font information and the text to render:</p>
<p><code><br />
var text:String = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ut odio. Curabitur faucibus, orci ut adipiscing lacinia, ipsum arcu suscipit nulla, vitae mollis sapien lectus ac nulla. Suspendisse eget massa. Fusce auctor nunc. Sed in nisl. In at dui. Nulla elementum gravida quam. Nullam scelerisque lacus ac mi."<br />
//  For our example, we'll use Times New Roman, Size 16, kerning on<br />
var fontDescription:FontDescription = new FontDescription("Times New Roman");<br />
var format:ElementFormat = new ElementFormat(fontDescription, 16.0); <br />
format.kerning = flash.text.engine.Kerning.ON;<br />
// create a text element, which TextBlock will consume in order to begin rendering lines<br />
var textElement:TextElement = new TextElement(text, format);<br />
var block:TextBlock = new TextBlock(textElement, null, null, "rotate0", "roman", 0, true, null, 16.0);<br />
// render a paragraph of the text using a width of 400px<br />
var previousLine:TextLine = null;<br />
while(true)<br />
{<br />
    var textLine:TextLine = block.createTextLine(previousLine, 400.0);<br />
    if(textLine != null &amp;&amp; block.textLineCreationResult == TextLineCreationResult.SUCCESS)<br />
    {<br />
        trace("new line of text:" + this.text.substr(textLine.textBlockBeginIndex, textLine.rawTextLength));<br />
        // align text 100px from the left, and offset each line from the last by a factor of 1.15 * font size<br />
        textLine.x += 100px;<br />
        textLine.y += linePosition;<br />
        this.addChild(textLine);<br />
        // TextBlock uses the previous line to know where it should start in the supplied TextElement,<br />
        // for the next call to createTextLine<br />
        previousLine = textLine; <br />
    }<br />
    else if (textLine == null &amp;&amp; this.block.textLineCreationResult == TextLineCreationResult.COMPLETE) <br />
    {   <br />
        // no more text left to render as TextLine                      <br />
        break;<br />
    }<br />
}       <br />
</code></p>
<p> <br />
This code results in the following:<br />
<img src="http://www.ownedthx.com/media/with-border.png" alt="" /></p>
<p> </p>
<p>With that small bit of effort, a paragraph is now created which represents the string of text and accompanying font information.</p>
<p> <br />
Taking this code a bit further to account for page margins, one can, as near as I can tell, recreate perfectly a paragraph found within Word by using the <strong>flash.text.engine</strong>, as shown at the top of this post.</p>
<p>By specifying the same paragraph width as parsed from the Word document, same font size and family, line breaks naturally occurred in our test application exactly where they occurred within Word, creating a very promising avenue to someday displaying a Word document in a web page, without the need for any special client software.</p>
<p>A very <a href="http://www.ownedthx.com/tutorial/fte_example_1.zip"> trivial example project</a> is available with build script (assumes the Flex SDK bin directory is in your path).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sethcall.com/blog/2009/04/27/flash-completely-dominates-csshtmljs-for-rendering-text-accurately/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>
