<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2019-08-13T19:12:06-06:00</updated><id>/feed.xml</id><title type="html">Megatome Technologies</title><subtitle>Occasional posts about development and other things.</subtitle><author><name>Chad Johnston</name></author><entry><title type="html">Identity Theft, And The Crooks May Be In Our Own Backyard</title><link href="/security/2017/04/27/identity-theft-and-the-crooks-may-be-in-our-own-backyard.html" rel="alternate" type="text/html" title="Identity Theft, And The Crooks May Be In Our Own Backyard" /><published>2017-04-27T00:00:00-06:00</published><updated>2017-04-27T00:00:00-06:00</updated><id>/security/2017/04/27/identity-theft-and-the-crooks-may-be-in-our-own-backyard</id><content type="html" xml:base="/security/2017/04/27/identity-theft-and-the-crooks-may-be-in-our-own-backyard.html">&lt;p&gt;Roughly two weeks ago, my wife received a letter in the mail informing her that her credit card application had been denied. Since she hadn’t applied for anything, our suspicion was immediately aroused.&lt;/p&gt;

&lt;p&gt;She called the company and confirmed that no account had been opened and had the transaction marked as fraudulent. The next step was to place a freeze on her credit to try to prevent any further issues.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*hqRCiBvkde7wkhS-hFgmnw.jpeg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Late last week, we got another letter from a different credit card company congratulating her on her new card and letting her know that her new card would be in the mail shortly.&lt;/p&gt;

&lt;p&gt;We figured that whoever had applied for the other card had applied for this one at the same time and this application had passed muster. A call to the company got the account closed and marked fraudulent as well.&lt;/p&gt;

&lt;p&gt;We kept checking her credit report and nothing new showed up, so we thought we were in the clear.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*AY2Q-Nzc60weLym7e7o6cg.jpeg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We get our mail at a cluster of mailboxes that are at various points in our neighborhood.&lt;/p&gt;

&lt;p&gt;Yesterday, there was no mail. Very unusual, but not unheard of.&lt;/p&gt;

&lt;p&gt;Today, there was no mail. Knowing I had an Amazon delivery waiting, I knew something was wrong. I confirmed with my neighbors that they’d received their mail then headed for the post office.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*tQzCf1Lv6oBqecsTEU_AtA.jpeg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Up until this point, this had been a crime of annoyance. Things like this are almost the background noise of living in a digital world with easy access to information. What I learned at the post office changed all of that.&lt;/p&gt;

&lt;p&gt;I found that someone had gone to the post office and put a hold on our mail — but only the mail addressed to my wife. Luckily, all of our mail was held or we may not have noticed anything wrong since my wife gets so little mail. The hold instructions clearly stated that my “wife” would be picking up the held mail.&lt;/p&gt;

&lt;p&gt;This means that there’s someone in my little town or surrounding area committing this crime. This isn’t anonymous anymore. There’s an actual person in driving distance doing this to us. I’m sure we weren’t specifically singled out for this; we may only be one of many. Still, it makes this situation feel personal.&lt;/p&gt;

&lt;p&gt;I don’t have any idea how this could have been prevented. The woman at the post office clearly did not believe me when I explained that nobody in our household placed the hold, and the idea of someone placing a hold maliciously wasn’t even in her realm of belief. She almost let me walk out with the bin of held mail without even checking my ID, but then she muttered that I could be a bad guy so she should check, I guess.&lt;/p&gt;

&lt;p&gt;Without diligent vetting, anyone can walk into the post office and place a hold on mail. With no vetting at all, someone can go online and place a mail hold on an address. There’s no way that I’ve found online or by talking to the postal clerk that allows you to protect your mail from this kind of tampering. I’d love it if I could fill out something that prevented holds from being placed unless my wife or I did it in person, verified by our IDs.&lt;/p&gt;

&lt;p&gt;We’re working with the police, who are hopeful that the crook will show up at some point to pick up the mail, or that they left some kind of trail when placing the hold. Until then, we keep a more diligent eye on everything.&lt;/p&gt;</content><author><name>Chad Johnston</name></author><category term="security" /><category term="identity" /><summary type="html">Local scammers attempted to steal my wife's identity.</summary></entry><entry><title type="html">Working with NodeJS source</title><link href="/development/2015/05/20/working-with-nodejs-source.html" rel="alternate" type="text/html" title="Working with NodeJS source" /><published>2015-05-20T00:00:00-06:00</published><updated>2015-05-20T00:00:00-06:00</updated><id>/development/2015/05/20/working-with-nodejs-source</id><content type="html" xml:base="/development/2015/05/20/working-with-nodejs-source.html">&lt;p&gt;I’ve developed an interest in contributing to the NodeJS project, especially since I found some things while working on my &lt;a href=&quot;https://github.com/iamthechad/sslinfo&quot;&gt;sslinfo&lt;/a&gt; module that could be improved in the x509 realm.&lt;/p&gt;

&lt;p&gt;I’m not comfortable building and running the Node source on my everyday machine since I don’t know what kinds of side effects and conflicts I might cause. It seemed only natural to use some kind of virtual machine based solution, but I’ve been having little luck getting an environment set up to my liking.&lt;/p&gt;

&lt;p&gt;I have a modest list of requirements that I’d like to satisfy with a VM-based solution:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Quick and repeatable VM creation&lt;/li&gt;
  &lt;li&gt;Access to the Node source from within the VM, for building/testing/deploying in a “clean” environment.&lt;/li&gt;
  &lt;li&gt;Access to the Node source from the host machine, for using my existing dev tools (TextMate, SublimeText) to modify code and documentation, and for using my existing Git tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, I’ve already got a set of tools in my Mac environment that I’m very accustomed to. I don’t want to reinvent that wheel by requiring a bunch more tools within the VM.&lt;/p&gt;

&lt;p&gt;My initial thought was to simply repurpose the &lt;a href=&quot;https://github.com/iamthechad/vagrant-ghpages&quot;&gt;Vagrant setup I use to manage this blog&lt;/a&gt;. It’s a simple setup, with a &lt;code class=&quot;highlighter-rouge&quot;&gt;config.vm.synced_folder &quot;../node/&quot;, &quot;/opt/node&quot;&lt;/code&gt; line in the Vagrantfile to map my already checked out NodeJS source into the VM.&lt;/p&gt;

&lt;p&gt;Once I had the VM running, I SSH’ed in and ran the following:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /opt/node
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make clean &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; out
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./configure
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The code builds with no errors, but 14 tests fail.&lt;/p&gt;

&lt;p&gt;Failed test summary -&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Path: simple/test-cluster-http-pipe
Error: &lt;span class=&quot;nb&quot;&gt;bind &lt;/span&gt;EPERM

Path: simple/test-fs-error-messages
assert.js:86
  throw new assert.AssertionError&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt;
        ^
AssertionError: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true

&lt;/span&gt;Command: out/Release/node /opt/node/test/simple/test-fs-error-messages.js
Message from syslogd@debian-7 at May 20 12:48:18 ...
 kernel:[  951.248484] Oops: 0002 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;#1] SMP&lt;/span&gt;

Path: simple/test-fs-symlink
Error: EPERM, link &lt;span class=&quot;s1&quot;&gt;'/opt/node/test/tmp/link1.js'&lt;/span&gt;

Path: simple/test-http-client-pipe-end
Error: listen EPERM

Path: simple/test-http-client-response-domain
Error: listen EPERM

Path: simple/test-http-unix-socket
Error: listen EPERM

Path: simple/test-net-pingpong
/opt/node/test/tmp/test.sock
Error: listen EPERM

Path: simple/test-net-pipe-connect-errors
Error: listen EPERM

Path: simple/test-pipe-address
Error: listen EPERM

Path: simple/test-pipe-stream
Error: listen EPERM

Path: simple/test-pipe-unref
Error: listen EPERM

Path: simple/test-repl
repl &lt;span class=&quot;nb&quot;&gt;test
&lt;/span&gt;Error: listen EPERM

Path: simple/test-tls-connect-pipe
Error: listen EPERM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Grrr, although there is a pattern. The majority of the failures have an &lt;code class=&quot;highlighter-rouge&quot;&gt;EPERM&lt;/code&gt; root cause.&lt;/p&gt;

&lt;p&gt;For this attempt, I didn’t bother setting a shared folder in the Vagrantfile. Parallels tools are installed, and they give me access to my Mac’s files through &lt;code class=&quot;highlighter-rouge&quot;&gt;/media/psf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The steps this time:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /media/psf/Home/Documents/workspaces/node &lt;span class=&quot;c&quot;&gt;#Yeah, that's where I keep my code.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make clean &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; out
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./configure
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;14 tests fail, just like before.&lt;/p&gt;

&lt;p&gt;Grrr again.&lt;/p&gt;

&lt;p&gt;I asked Twitter. I asked the NodeJS IRC channel. I Googled. Finally, I found a single page that offered anecdotal evidence that &lt;a href=&quot;http://samplacette.com/node-js-net-module-server-listen-socket-eperm-error/&quot;&gt;NodeJS cannot create sockets in a shared directory in a VM&lt;/a&gt;. Looking back at the failing tests, they were all socket or pipe related.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I have not been able to find “official” confirmation of this. If anyone can confirm or deny, please let me know.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;attempt-three-vagrant-vm-with-sftpsync&quot;&gt;Attempt Three: Vagrant VM with SFTP Sync&lt;/h3&gt;

&lt;p&gt;I didn’t bother with shared folders at all this time. I installed the handy &lt;a href=&quot;http://wbond.net/sublime_packages/sftp&quot;&gt;SFTP plugin&lt;/a&gt; for Sublime Text and synced my local NodeJS source into the VM.&lt;/p&gt;

&lt;p&gt;Steps again:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /home/cjohnston/node
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make clean &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; out
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./configure
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Only 1 test fails this time, but it’s a new failure.&lt;/p&gt;

&lt;p&gt;Failed test summary -&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Path: simple/test-fs-realpath
Error: EEXIST, file already exists &lt;span class=&quot;s1&quot;&gt;'/home/cjohnston/node/test/fixtures/nested-index/one/symlink1-dir'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I honestly have no idea why this test fails. Maybe it’s file permissions due to the SFTP copy?&lt;/p&gt;

&lt;h3 id=&quot;attempt-four-give-up-and-check-out-the-code-in-thevm&quot;&gt;Attempt Four: Give up and check out the code in the VM&lt;/h3&gt;

&lt;p&gt;As expected, building and running the tests works perfectly with this method. However, I’ve also lost the ability to expose the code to the host OS. My Vagrant VM doesn’t have a windowing system installed, so I’m down to &lt;code class=&quot;highlighter-rouge&quot;&gt;vi&lt;/code&gt; for code edits, and checking out the source in parallel on my Mac for making and previewing doc changes.&lt;/p&gt;

&lt;p&gt;At this point, I’d be happy for any input on how to achieve my development goals as stated at the top of the post. Solving the issue of being able to open sockets and pipes in a shared folder would be fantastic, but I don’t know how hard that problem would be to solve.&lt;/p&gt;</content><author><name>Chad Johnston</name></author><category term="development" /><category term="nodejs" /><summary type="html">I've been trying to set up a development environment for working on NodeJS source, with little luck.</summary></entry><entry><title type="html">Simple Data Analysis with Hive</title><link href="/development/2013/07/17/simple-data-analysis-with-hive.html" rel="alternate" type="text/html" title="Simple Data Analysis with Hive" /><published>2013-07-17T00:00:00-06:00</published><updated>2013-07-17T00:00:00-06:00</updated><id>/development/2013/07/17/simple-data-analysis-with-hive</id><content type="html" xml:base="/development/2013/07/17/simple-data-analysis-with-hive.html">&lt;p&gt;Hive is a data warehouse system for Hadoop that facilitates easy data summarization, ad-hoc queries, and the analysis of large datasets stored in Hadoop compatible file systems. Hive provides a mechanism to project structure onto this data and query the data using a SQL-like language called HiveQL.&lt;/p&gt;

&lt;p&gt;This is a simple getting started example that’s based upon “&lt;a href=&quot;http://www.orzota.com/hive-for-beginners/&quot;&gt;Hive for Beginners&lt;/a&gt;”, with what I feel is a bit more useful information.&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;/development/2013/07/16/simple-data-analysis-with-pig.html&quot;&gt;This example is also available using Pig.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The installation and configuration of Hadoop and Hive is beyond the scope of this article. If you’re just getting started, I would highly recommend grabbing one of &lt;a href=&quot;https://ccp.cloudera.com/display/SUPPORT/Cloudera+QuickStart+VM&quot;&gt;Cloudera’s pre-built virtual machines&lt;/a&gt; that have everything you need.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Cloudera’s VMs have changed substantially since this article was written. I have not been able to verify that the new VMs will work with these instructions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m assuming that you will be running the following steps using the &lt;a href=&quot;https://ccp.cloudera.com/display/SUPPORT/Cloudera+QuickStart+VM&quot;&gt;Cloudera VM&lt;/a&gt;, logged in as the cloudera user. If your setup is different, adjust accordingly.&lt;/p&gt;

&lt;h3 id=&quot;step-1-preparing-thedata&quot;&gt;Step 1: Preparing the Data&lt;/h3&gt;

&lt;p&gt;Like “&lt;a href=&quot;http://www.orzota.com/hive-for-beginners/&quot;&gt;Hive for Beginners&lt;/a&gt;”, we’re going to use the &lt;a href=&quot;http://www.informatik.uni-freiburg.de/~cziegler/BX/&quot;&gt;Book Crossing Dataset&lt;/a&gt;. Download the CSV dump and extract the files. We’re interested in the &lt;code class=&quot;highlighter-rouge&quot;&gt;BX-Books.csv&lt;/code&gt; data file.&lt;/p&gt;

&lt;p&gt;Type &lt;code class=&quot;highlighter-rouge&quot;&gt;head BX-Books.csv&lt;/code&gt; to see the first few lines of the raw data. You’ll notice that’s it’s not really comma-delimited; the delimiter is ‘&lt;code class=&quot;highlighter-rouge&quot;&gt;;&lt;/code&gt;’. There are also some escaped HTML entities we can clean up, and the quotes around all of the values can be removed.&lt;/p&gt;

&lt;p&gt;The first line in the file looks like this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ISBN&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Book-Title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Book-Author&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Year-Of-Publication&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Publisher&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Image-URL-S&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Image-URL-M&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Image-URL-L&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This lines defines the data format of the fields in the file. We’ll want to refer back to it later.&lt;/p&gt;

&lt;p&gt;Open a terminal and enter:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sed &lt;span class=&quot;s1&quot;&gt;'s/\&amp;amp;amp;/\&amp;amp;/g'&lt;/span&gt; BX-Books.csv | sed &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1d'&lt;/span&gt; |sed &lt;span class=&quot;s1&quot;&gt;'s/;/$$$/g'&lt;/span&gt; | sed &lt;span class=&quot;s1&quot;&gt;'s/&quot;$$$&quot;/&quot;;&quot;/g'&lt;/span&gt; | sed &lt;span class=&quot;s1&quot;&gt;'s/&quot;//g'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; BX-BooksCorrected.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Replace all &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;amp;amp;&lt;/code&gt; instances with &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;amp;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Remove the first (header) line&lt;/li&gt;
  &lt;li&gt;Change all semicolons to &lt;code class=&quot;highlighter-rouge&quot;&gt;$$$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Change all &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;$$$&quot;&lt;/code&gt; instances into &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;;&quot;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Remove all &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;&lt;/code&gt; characters&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Steps 3 and 4 may look strange, but some of the field content may contain semicolons. In this case, they will be converted to &lt;code class=&quot;highlighter-rouge&quot;&gt;$$$&lt;/code&gt;, but they will not match the &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;$$$&quot;&lt;/code&gt; pattern, and will not be converted back into semicolons and mess up the import process.&lt;/p&gt;

&lt;h3 id=&quot;step-2-importing-thedata&quot;&gt;Step 2: Importing the Data&lt;/h3&gt;

&lt;p&gt;Now that we have some normalized data, we need to add it to the Hadoop file system (HDFS) so that Hive can access it. In the terminal, type:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;hadoop fs &lt;span class=&quot;nt&quot;&gt;-mkdir&lt;/span&gt; input
hadoop fs &lt;span class=&quot;nt&quot;&gt;-put&lt;/span&gt; /path/to/BX-BooksCorrected.txt input
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(Use the correct path to the &lt;code class=&quot;highlighter-rouge&quot;&gt;BX-BooksCorrected.txt&lt;/code&gt; file.)&lt;/p&gt;

&lt;h3 id=&quot;step-3-runninghive&quot;&gt;Step 3: Running Hive&lt;/h3&gt;

&lt;p&gt;Enter &lt;code class=&quot;highlighter-rouge&quot;&gt;hive&lt;/code&gt; at the console to start Hive.&lt;/p&gt;

&lt;p&gt;Once Hive has started, you’ll see the &lt;code class=&quot;highlighter-rouge&quot;&gt;hive&amp;gt;&lt;/code&gt; command prompt. Let’s verify that our file did get loaded into HDFS.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dfs &lt;span class=&quot;nt&quot;&gt;-ls&lt;/span&gt; input&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-4-analyzing-thedata&quot;&gt;Step 4: Analyzing the Data&lt;/h3&gt;

&lt;p&gt;Now that we have the data ready, let’s do something with it. The simple example is to see how many books were published per year. We’ll start with that, then see if we can do a bit more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Load the data into a Hive table:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CREATE TABLE IF NOT EXISTS BookData
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ISBN STRING,
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; BookTitle STRING,
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; BookAuthor STRING,
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; YearOfPublication INT,
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Publisher STRING&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ROW FORMAT DELIMITED
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; FIELDS TERMINATED BY &lt;span class=&quot;s1&quot;&gt;'\;'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; STORED AS TEXTFILE&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

LOAD DATA INPATH &lt;span class=&quot;s1&quot;&gt;'/user/cloudera/input/BX-BooksCorrected.txt'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; OVERWRITE INTO TABLE BookData&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(HQL commands are terminated with semicolons. If you press Return on a line without terminating it, you’ll get the &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;gt;&lt;/code&gt; character, indicating that the command has been continued and not entered yet.)
 This creates a Hive table named &lt;code class=&quot;highlighter-rouge&quot;&gt;BookData&lt;/code&gt; and loads the information from HDFS into it. Hive expects data to be tab-delimited by default, but ours is not; we have to tell it that semicolons are field separators by providing the &lt;code class=&quot;highlighter-rouge&quot;&gt;FIELDS TERMINATED BY&lt;/code&gt; argument. You’ll notice that we left off all of the “&lt;code class=&quot;highlighter-rouge&quot;&gt;Image-URL-XXX&lt;/code&gt;” fields; we don’t need them for analysis, and Hive will ignore fields that we don’t tell it to load.&lt;/p&gt;

&lt;p&gt;If you want to see what the loaded data structure looks like, you can use the &lt;code class=&quot;highlighter-rouge&quot;&gt;DESCRIBE&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;DESCRIBE BookData&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;finding-books-byyear&quot;&gt;Finding books by year&lt;/h3&gt;

&lt;p&gt;We’ll start with the simple analysis of how many books were written by year. In Hive, this can be accomplished with a single query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get number of books by year:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SELECT YearOfPublication, COUNT&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;BookTitle&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; FROM BookData GROUP BY YearOfPublication&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll see a listing of years, along with the number of books for that year. You may notice that some of the values don’t make much sense; there should be no year 0, nor should there be entries for a blank year. We’ll clean those problems up in the next analysis.&lt;/p&gt;

&lt;h3 id=&quot;more-advancedanalysis&quot;&gt;More Advanced Analysis&lt;/h3&gt;

&lt;p&gt;There’s a lot more data in the set beyond years and books counts. What if we wanted to see books published per year by author? Why don’t we go a step farther and group those results by publisher as well?&lt;/p&gt;

&lt;p&gt;Let’s do a little bit of cleanup on the data to eliminate the unwanted years.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;INSERT OVERWRITE TABLE BookData
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; SELECT BookData.&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; FROM BookData WHERE YearOfPublication &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will only keep records where we have a positive year of publication value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generating the final results is again a single query:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SELECT Publisher, BookAuthor, YearOfPublication, COUNT&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;BookTitle&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; FROM BookData
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; GROUP BY Publisher, BookAuthor, YearOfPublication&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At last! We have our results.&lt;/p&gt;

&lt;p&gt;(Want to compare the Hive steps with Pig? &lt;a href=&quot;/development/2013/07/16/simple-data-analysis-with-pig.html&quot;&gt;Here’s the same example using Pig.&lt;/a&gt;)&lt;/p&gt;</content><author><name>Chad Johnston</name></author><category term="development" /><category term="hive" /><summary type="html">Follow this simple example to get started analyzing real-world data with Hive and Hadoop.</summary></entry><entry><title type="html">Simple Data Analysis with Pig</title><link href="/development/2013/07/16/simple-data-analysis-with-pig.html" rel="alternate" type="text/html" title="Simple Data Analysis with Pig" /><published>2013-07-16T00:00:00-06:00</published><updated>2013-07-16T00:00:00-06:00</updated><id>/development/2013/07/16/simple-data-analysis-with-pig</id><content type="html" xml:base="/development/2013/07/16/simple-data-analysis-with-pig.html">&lt;p&gt;Pig is a platform that works with large data sets for the purpose of analysis. The Pig dialect is called Pig Latin, and the Pig Latin commands get compiled into MapReduce jobs that can be run on a suitable platform, like Hadoop.&lt;/p&gt;

&lt;p&gt;This is a simple getting started example that’s based upon “&lt;a href=&quot;http://www.orzota.com/pig-for-beginners/&quot;&gt;Pig for Beginners&lt;/a&gt;”, with what I feel is a bit more useful information.&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://megatome.com/simple-data-analysis-with-hive-cb4a48700419#.xwarutlku&quot;&gt;This example is also available using Hive.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The installation and configuration of Hadoop and Pig is beyond the scope of this article. If you’re just getting started, I would highly recommend grabbing one of &lt;a href=&quot;https://www.cloudera.com/downloads/quickstart_vms/5-8.html&quot;&gt;Cloudera’s pre-built virtual machines&lt;/a&gt; that have everything you need.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Cloudera’s VMs have changed substantially since this article was written. I have not been able to verify that the new VMs will work with these instructions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m assuming that you will be running the following steps using the &lt;a href=&quot;https://www.cloudera.com/downloads/quickstart_vms/5-8.html&quot;&gt;Cloudera VM&lt;/a&gt;, logged in as the &lt;code class=&quot;highlighter-rouge&quot;&gt;cloudera&lt;/code&gt; user. If your setup is different, adjust accordingly.&lt;/p&gt;

&lt;h3 id=&quot;step-1-preparing-thedata&quot;&gt;Step 1: Preparing the Data&lt;/h3&gt;

&lt;p&gt;Like “&lt;a href=&quot;http://www.orzota.com/pig-for-beginners/&quot;&gt;Pig for Beginners&lt;/a&gt;”, we’re going to use the &lt;a href=&quot;http://www.informatik.uni-freiburg.de/~cziegler/BX/&quot;&gt;Book Crossing Dataset&lt;/a&gt;. Download the CSV dump and extract the files. We’re interested in the &lt;code class=&quot;highlighter-rouge&quot;&gt;BX-Books.csv&lt;/code&gt; data file.&lt;/p&gt;

&lt;p&gt;Type &lt;code class=&quot;highlighter-rouge&quot;&gt;head BX-Books.csv&lt;/code&gt; to see the first few lines of the raw data. You’ll notice that’s it’s not really comma-delimited; the delimiter is ‘&lt;code class=&quot;highlighter-rouge&quot;&gt;;&lt;/code&gt;‘. There are also some escaped HTML entities we can clean up, and the quotes around all of the values can be removed.&lt;/p&gt;

&lt;p&gt;The first line in the file looks like this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ISBN&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Book-Title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Book-Author&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Year-Of-Publication&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Publisher&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Image-URL-S&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Image-URL-M&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Image-URL-L&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This lines defines the data format of the fields in the file. We’ll want to refer back to it later.&lt;/p&gt;

&lt;p&gt;Open a terminal and enter:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sed &lt;span class=&quot;s1&quot;&gt;'s/\&amp;amp;amp;/\&amp;amp;/g'&lt;/span&gt; BX-Books.csv | sed &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1d'&lt;/span&gt; |sed &lt;span class=&quot;s1&quot;&gt;'s/;/$$$/g'&lt;/span&gt; | sed &lt;span class=&quot;s1&quot;&gt;'s/&quot;$$$&quot;/&quot;;&quot;/g'&lt;/span&gt; | sed &lt;span class=&quot;s1&quot;&gt;'s/&quot;//g'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; BX-BooksCorrected.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Replace all &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;amp;amp;&lt;/code&gt; instances with &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;amp;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Remove the first (header) line&lt;/li&gt;
  &lt;li&gt;Change all semicolons to &lt;code class=&quot;highlighter-rouge&quot;&gt;$$$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Change all &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;$$$&quot;&lt;/code&gt; instances into &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;;&quot;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Remove all &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;&lt;/code&gt; characters&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Steps 3 and 4 may look strange, but some of the field content may contain semicolons. In this case, they will be converted to &lt;code class=&quot;highlighter-rouge&quot;&gt;$$$&lt;/code&gt;, but they will not match the &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;$$$&quot;&lt;/code&gt; pattern, and will not be converted back into semicolons and mess up the import process.&lt;/p&gt;

&lt;h3 id=&quot;step-2-importing-thedata&quot;&gt;Step 2: Importing the Data&lt;/h3&gt;

&lt;p&gt;Now that we have some normalized data, we need to add it to the Hadoop file system (HDFS) so that Pig can access it. This can be accomplished from the command line as well as within Pig itself. For this example, we’ll use the command line. In the terminal, type:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;hadoop fs &lt;span class=&quot;nt&quot;&gt;-mkdir&lt;/span&gt; input
hadoop fs &lt;span class=&quot;nt&quot;&gt;-put&lt;/span&gt; /path/to/BX-BooksCorrected.txt input
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(Use the correct path to the &lt;code class=&quot;highlighter-rouge&quot;&gt;BX-BooksCorrected.txt&lt;/code&gt; file.)&lt;/p&gt;

&lt;h3 id=&quot;step-3-runningpig&quot;&gt;Step 3: Running Pig&lt;/h3&gt;

&lt;p&gt;There are several ways to run Pig. We’re going to run in MapReduce mode against the local node. MapReduce mode runs against the HDFS, which is why we needed to import the file in the previous step.&lt;/p&gt;

&lt;p&gt;Enter &lt;code class=&quot;highlighter-rouge&quot;&gt;pig&lt;/code&gt; at the console to start Pig.&lt;/p&gt;

&lt;p&gt;Once Pig has started, you’ll see the &lt;code class=&quot;highlighter-rouge&quot;&gt;grunt&amp;gt;&lt;/code&gt; command prompt. Let’s verify that our file did get loaded into HDFS.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;ls
&lt;/span&gt;hdfs://localhost.localdomain:8020/user/cloudera/input	&amp;lt;dir&amp;gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;input
&lt;span class=&quot;nb&quot;&gt;ls
&lt;/span&gt;hdfs://localhost.localdomain:8020/user/cloudera/input/BX-BooksCorrected.txt	&amp;lt;dir&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-4-analyzing-thedata&quot;&gt;Step 4: Analyzing the Data&lt;/h3&gt;

&lt;p&gt;Now that we have the data ready, let’s do something with it. The simple example is to see how many books were published per year. We’ll start with that, then see if we can do a bit more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Load the data into a Pig collection:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;books &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; LOAD &lt;span class=&quot;s1&quot;&gt;'/user/cloudera/input/BX-BooksCorrected.txt'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; USING PigStorage&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;';'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; AS
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ISBN:chararray, BookTitle:chararray,
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; BookAuthor:chararray, YearOfPublication:int,
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Publisher:chararray&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(Pig Latin commands are terminated with semicolons. If you press Return on a line without terminating it, you’ll get the &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;gt;&amp;gt;&lt;/code&gt; characters, indicating that the command has been continued and not entered yet.)
 This line loads the information from HDFS into a Pig collection named &lt;code class=&quot;highlighter-rouge&quot;&gt;books&lt;/code&gt;. Pig expects data to be tab-delimited by default, but ours is not; we have to tell it that semicolons are field separators by providing the &lt;code class=&quot;highlighter-rouge&quot;&gt;PigStorage()&lt;/code&gt; argument. The &lt;code class=&quot;highlighter-rouge&quot;&gt;AS&lt;/code&gt; clause defines how the fields in the file are mapped into Pig data types. You’ll notice that we left off all of the “&lt;code class=&quot;highlighter-rouge&quot;&gt;Image-URL-XXX&lt;/code&gt;” fields; we don’t need them for analysis, and Pig will ignore fields that we don’t tell it to load.&lt;/p&gt;

&lt;p&gt;If you want to see what the loaded data structure looks like, you can use the &lt;code class=&quot;highlighter-rouge&quot;&gt;DESCRIBE&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;DESCRIBE books&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
books: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;ISBN: chararray,BookTitle: chararray,BookAuthor: chararray,YearOfPublication: int,Publisher: chararray&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;finding-books-byyear&quot;&gt;Finding books by year&lt;/h3&gt;

&lt;p&gt;We’ll start with the simple analysis of how many books were written by year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Group the collection by year of publication:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;groupByYear &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; GROUP books BY YearOfPublication&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

DESCRIBE groupByYear&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
groupByYear: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;group: int,books: &lt;span class=&quot;o&quot;&gt;{(&lt;/span&gt;ISBN: chararray,BookTitle: chararray,BookAuthor: chararray,YearOfPublication: int,Publisher: chararray&lt;span class=&quot;o&quot;&gt;)}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is a lot like a Java Map. The &lt;code class=&quot;highlighter-rouge&quot;&gt;groupByYear&lt;/code&gt; collection contains all unique year values, along with a list holding the full entry of each book that belongs to that year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generate book count by year:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;countByYear &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FOREACH groupByYear
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; GENERATE group AS YearOfPublication, COUNT&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; AS BookCount&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

DESCRIBE countByYear&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
countByYear: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;YearOfPublication: int,BookCount: int&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is the meat of the operation. The &lt;code class=&quot;highlighter-rouge&quot;&gt;FOREACH&lt;/code&gt; loops over the &lt;code class=&quot;highlighter-rouge&quot;&gt;groupByYear&lt;/code&gt; collection, and we &lt;code class=&quot;highlighter-rouge&quot;&gt;GENERATE&lt;/code&gt; values. Our output is defined using some values available to us within the &lt;code class=&quot;highlighter-rouge&quot;&gt;FOREACH&lt;/code&gt;. We first take &lt;code class=&quot;highlighter-rouge&quot;&gt;group&lt;/code&gt;, which is an alias for the grouping value and say to place it in our new collection as an item named &lt;code class=&quot;highlighter-rouge&quot;&gt;YearOfPublication&lt;/code&gt;. (This value is also available as &lt;code class=&quot;highlighter-rouge&quot;&gt;$0&lt;/code&gt;.) The next value &lt;code class=&quot;highlighter-rouge&quot;&gt;$1&lt;/code&gt; is an alias for the list of book entries for that group. We only care about the number of books, so we use &lt;code class=&quot;highlighter-rouge&quot;&gt;COUNT&lt;/code&gt; and give it the name &lt;code class=&quot;highlighter-rouge&quot;&gt;BookCount&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We have the results, but how do we see them? We could store them back into HDFS and extract them that way, or we can use the &lt;code class=&quot;highlighter-rouge&quot;&gt;DUMP&lt;/code&gt; command.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;DUMP countByYear&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll see a listing of years, along with the number of books for that year. You may notice that some of the values don’t make much sense; there should be no year 0, nor should there be entries for a blank year. We’ll clean those problems up in the next analysis.&lt;/p&gt;

&lt;h3 id=&quot;more-advancedanalysis&quot;&gt;More Advanced Analysis&lt;/h3&gt;

&lt;p&gt;There’s a lot more data in the set beyond years and books counts. What if we wanted to see books published per year by author? Why don’t we go a step farther and group those results by publisher as well?&lt;/p&gt;

&lt;p&gt;You should still have your &lt;code class=&quot;highlighter-rouge&quot;&gt;books&lt;/code&gt; collection defined if you haven’t exited your Pig session. You can redefine it easily by following the above steps again. Let’s do a little bit of cleanup on the data this time, however.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;books &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FILTER books BY YearOfPublication &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will only keep records where we have a positive year of publication value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now, we need to create a set of all authors, and all years they wrote books:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pivot &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FOREACH &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;GROUP books BY BookAuthor&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; GENERATE group AS BookAuthor, FLATTEN&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;books.YearOfPublication&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; AS Year&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that I’ve inlined the group creation in the &lt;code class=&quot;highlighter-rouge&quot;&gt;FOREACH&lt;/code&gt; statement. It should be obvious that we’re grouping &lt;code class=&quot;highlighter-rouge&quot;&gt;books&lt;/code&gt; by author.
 This statement also introduces the &lt;code class=&quot;highlighter-rouge&quot;&gt;FLATTEN&lt;/code&gt; operation. We know that the &lt;code class=&quot;highlighter-rouge&quot;&gt;GROUP&lt;/code&gt; operation creates a collection where each key corresponds to a list of values; &lt;code class=&quot;highlighter-rouge&quot;&gt;FLATTEN&lt;/code&gt; “flattens” this list to generate entries for each list value. (See the &lt;a href=&quot;http://pig.apache.org/docs/r0.11.1/basic.html#flatten&quot;&gt;Pig Latin reference for&lt;/a&gt; a more detailed definition.) You may want to &lt;code class=&quot;highlighter-rouge&quot;&gt;DUMP&lt;/code&gt; the &lt;code class=&quot;highlighter-rouge&quot;&gt;pivot&lt;/code&gt; collection to see how the flattening works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create author book count by year:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;authorYearGroup &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; GROUP pivot BY &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;BookAuthor, Year&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

with_count &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FOREACH authorYearGroup
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; GENERATE FLATTEN&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;group&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, COUNT&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;pivot&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; as count&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

DESCRIBE with_count&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

with_count: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;group::BookAuthor: chararray,group::Year: int, count: long&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This time, we’re grouping on 2 fields. This will find all (author, year) combinations. We then execute a &lt;code class=&quot;highlighter-rouge&quot;&gt;FOREACH&lt;/code&gt; over the group; this time, however, we’re using &lt;code class=&quot;highlighter-rouge&quot;&gt;FLATTEN&lt;/code&gt; on the &lt;code class=&quot;highlighter-rouge&quot;&gt;group&lt;/code&gt; which will expand to &lt;code class=&quot;highlighter-rouge&quot;&gt;BookAuthor&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Year&lt;/code&gt;. We also grab the count of items to get the number of books for that author/year combination. You can see the resulting data structure in the &lt;code class=&quot;highlighter-rouge&quot;&gt;DESCRIBE&lt;/code&gt; results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let’s group those results a little better:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;author_result &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FOREACH &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;GROUP with_count BY BookAuthor&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; order_by_count &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; ORDER with_count BY count DESC&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; GENERATE group AS Author, order_by_count.&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Year, count&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; AS Books&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

DESCRIBE author_result&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

author_result: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;Author: chararray,Books: &lt;span class=&quot;o&quot;&gt;{(&lt;/span&gt;group::Year: int,count: long&lt;span class=&quot;o&quot;&gt;)}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’re running a &lt;code class=&quot;highlighter-rouge&quot;&gt;FOREACH&lt;/code&gt; that looks different than the ones we’ve seen to this point. This nested structure lets us perform some extra steps before generation of values. In this case, we’re sorting the book count, then placing the year/count tuples into the collection with the author.&lt;/p&gt;

&lt;p&gt;Group the author results by publisher:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pub_auth &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FOREACH books GENERATE Publisher, BookAuthor&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

distinct_authors &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FOREACH &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;GROUP pub_auth BY Publisher&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; da &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; DISTINCT pub_auth.BookAuthor&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; GENERATE group AS Publisher, da AS Author&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

distinct_flat &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FOREACH distinct_authors GENERATE Publisher, FLATTEN&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Author&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; AS Author&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First, we use a projection to extract only the publisher and author from the books collection. This is a &lt;a href=&quot;http://pig.apache.org/docs/r0.11.1/perf.html#projection&quot;&gt;recommended practice&lt;/a&gt; as it helps with performance. In this &lt;code class=&quot;highlighter-rouge&quot;&gt;FOREACH&lt;/code&gt;, we’re grabbing the distinct authors per publisher. This collection is then flattened into &lt;code class=&quot;highlighter-rouge&quot;&gt;distinct_flat&lt;/code&gt;, and we end up with a publisher/author list, similar to the author/year collection previously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Join the results so far:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;joined &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; JOIN distinct_flat BY Author, author_result BY Author&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
filtered &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FOREACH joined GENERATE
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; distinct_flat::Publisher AS Publisher,
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; distinct_flat::Author AS Author,
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; author_result::Books AS Books&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we’re joining the author/year results with the publisher/author results. The “&lt;code class=&quot;highlighter-rouge&quot;&gt;::&lt;/code&gt;” syntax may look a little different than what we’ve seen before; it’s a dereference operator, and it’s used when you need to unambiguously declare a column. Try &lt;code class=&quot;highlighter-rouge&quot;&gt;DESCRIBE&lt;/code&gt; on &lt;code class=&quot;highlighter-rouge&quot;&gt;joined&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;filtered&lt;/code&gt; to see the structure difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generate the final results:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;result &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; FOREACH &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;GROUP filtered BY Publisher&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; order_by_pub &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; ORDER filtered BY Publisher ASC&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; GENERATE group AS Publisher, order_by_pub.&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Author, Books&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This should be familiar by now. We sort publishers, then generate a collection of publishers/authors/books.&lt;/p&gt;

&lt;p&gt;At last! We have our results. You can &lt;code class=&quot;highlighter-rouge&quot;&gt;DUMP&lt;/code&gt; them, but let’s also save the results back into HDFS.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;STORE result INTO &lt;span class=&quot;s1&quot;&gt;'/user/cloudera/publisher_books'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you can exit Pig with “&lt;code class=&quot;highlighter-rouge&quot;&gt;quit&lt;/code&gt;”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let’s get a file listing:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;hadoop fs &lt;span class=&quot;nt&quot;&gt;-ls&lt;/span&gt; publisher_books
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hadoop stores &lt;code class=&quot;highlighter-rouge&quot;&gt;publisher_books&lt;/code&gt; as a directory with associated files. Our actual data is in &lt;code class=&quot;highlighter-rouge&quot;&gt;part-r-00000&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;hadoop fs &lt;span class=&quot;nt&quot;&gt;-cat&lt;/span&gt; publisher_books/part-r-00000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(Want to compare the Pig steps with Hive? &lt;a href=&quot;/development/2013/07/17/simple-data-analysis-with-hive.html&quot;&gt;Here’s the same example using Hive.&lt;/a&gt;)&lt;/p&gt;</content><author><name>Chad Johnston</name></author><category term="development" /><category term="pig" /><summary type="html">Follow this simple example to get started analyzing real-world data with Apache Pig and Hadoop.</summary></entry><entry><title type="html">iOS6 table views and accessory segues</title><link href="/development/2012/10/25/ios6-table-views-and-accessory-segues.html" rel="alternate" type="text/html" title="iOS6 table views and accessory segues" /><published>2012-10-25T00:00:00-06:00</published><updated>2012-10-25T00:00:00-06:00</updated><id>/development/2012/10/25/ios6-table-views-and-accessory-segues</id><content type="html" xml:base="/development/2012/10/25/ios6-table-views-and-accessory-segues.html">&lt;p&gt;If you’re performing segues on a table row selection, you’re probably used to doing something like this in the &lt;code class=&quot;highlighter-rouge&quot;&gt;prepareForSegue:&lt;/code&gt; method:&lt;/p&gt;

&lt;div class=&quot;language-objc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prepareForSegue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIStoryboardSegue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;segue&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sender&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;segue&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isEqualToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&quot;mySegueIdentifier&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;NSIndexPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tableView&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;indexPathForSelectedRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;some&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;work&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In iOS6, segues can now be connected from a table cell’s accessory action. When making this connection, however, the &lt;code class=&quot;highlighter-rouge&quot;&gt;indexPathForSelectedRow&lt;/code&gt; returns &lt;code class=&quot;highlighter-rouge&quot;&gt;nil&lt;/code&gt;. The &lt;code class=&quot;highlighter-rouge&quot;&gt;prepareForSegue:&lt;/code&gt; method has a &lt;code class=&quot;highlighter-rouge&quot;&gt;sender&lt;/code&gt; parameter. In the case of an accessory action, this parameter is a &lt;code class=&quot;highlighter-rouge&quot;&gt;UITableViewCell&lt;/code&gt;. Knowing this, we can get the correct &lt;code class=&quot;highlighter-rouge&quot;&gt;indexPath&lt;/code&gt; like this:&lt;/p&gt;

&lt;div class=&quot;language-objc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prepareForSegue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIStoryboardSegue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;segue&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sender&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;segue&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isEqualToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&quot;mySegueIdentifier&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;NSIndexPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tableView&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;indexPathForCell&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;some&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>Chad Johnston</name></author><category term="ios" /><category term="development" /><summary type="html">Getting the correct indexPath for a table cell's accessory action segue is different than for a cell selection segue.</summary></entry><entry><title type="html">Optimizing images for iOS (and more)</title><link href="/development/2012/09/21/optimizing-images-for-ios-and-more.html" rel="alternate" type="text/html" title="Optimizing images for iOS (and more)" /><published>2012-09-21T00:00:00-06:00</published><updated>2012-09-21T00:00:00-06:00</updated><id>/development/2012/09/21/optimizing-images-for-ios-and-more</id><content type="html" xml:base="/development/2012/09/21/optimizing-images-for-ios-and-more.html">&lt;p&gt;Now that Apple is &lt;a href=&quot;http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/mobilehig/IconsImages/IconsImages.html&quot;&gt;requiring launch images&lt;/a&gt; in all iOS apps, many developers will see their application size increase, perhaps drastically. I use a fantastic (and free!) tool called &lt;a href=&quot;http://imageoptim.com/&quot;&gt;ImageOptim&lt;/a&gt; to reduce the size of the images in my projects.&lt;/p&gt;

&lt;p&gt;I was able to get over 65% file size reduction on my iPad launch images, and well over 50% on the iPhone images. Of course, your mileage may vary but it’s certainly worth checking out.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://imageoptim.com/&quot;&gt;ImageOptim&lt;/a&gt; isn’t limited to iOS apps. It’s useful wherever you may have a need to for reduced PNG file sizes.&lt;/p&gt;</content><author><name>Chad Johnston</name></author><category term="development" /><category term="ios" /><summary type="html">A simple tool for reducing PNG file sizes.</summary></entry><entry><title type="html">Supporting the iPhone 5 Screen</title><link href="/development/2012/09/20/supporting-the-iphone-5-screen.html" rel="alternate" type="text/html" title="Supporting the iPhone 5 Screen" /><published>2012-09-20T00:00:00-06:00</published><updated>2012-09-20T00:00:00-06:00</updated><id>/development/2012/09/20/supporting-the-iphone-5-screen</id><content type="html" xml:base="/development/2012/09/20/supporting-the-iphone-5-screen.html">&lt;p&gt;I had to dig a bit to find this information when adding iPhone 5 support to my app. It’s pretty easy: &lt;strong&gt;you need to supply a 640px by 1136px launch image&lt;/strong&gt;. That’s it. Of course, there may be layout issues that need tending to afterwards, but that’s a different story.&lt;/p&gt;

&lt;p&gt;I suspect that Apple forced the inclusion of the launch image to make all devs use them. I know quite a few apps that don’t have launch images, even though &lt;a href=&quot;http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/mobilehig/IconsImages/IconsImages.html&quot;&gt;Apple’s HIG says they’re required&lt;/a&gt;.&lt;/p&gt;</content><author><name>Chad Johnston</name></author><category term="ios" /><category term="development" /><summary type="html">Adding iPhone 5 support to your app.</summary></entry><entry><title type="html">Setting UITableView with grouped style background in iOS</title><link href="/development/2012/09/11/setting-uitableview-with-grouped-style-background-in-ios.html" rel="alternate" type="text/html" title="Setting UITableView with grouped style background in iOS" /><published>2012-09-11T00:00:00-06:00</published><updated>2012-09-11T00:00:00-06:00</updated><id>/development/2012/09/11/setting-uitableview-with-grouped-style-background-in-ios</id><content type="html" xml:base="/development/2012/09/11/setting-uitableview-with-grouped-style-background-in-ios.html">&lt;p&gt;Setting the background of a &lt;code class=&quot;highlighter-rouge&quot;&gt;UITableView&lt;/code&gt; is a simple operation in most cases. In my latest app, we set the background to a nice texture with a line like this:&lt;/p&gt;

&lt;div class=&quot;language-objc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tableView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backgroundColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIColor&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;colorWithPatternImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIImage&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;imageNamed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;myFancyBackground.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For some reason, when a &lt;code class=&quot;highlighter-rouge&quot;&gt;UITableView&lt;/code&gt; with the grouped style is presented in a popover, this code does not work. It turns out that grouped table views have a custom &lt;code class=&quot;highlighter-rouge&quot;&gt;backgroundView&lt;/code&gt; property. I don’t know why this property only takes precedence when the table is in a popover, but here’s how to fix it to display your custom background:&lt;/p&gt;

&lt;div class=&quot;language-objc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tableView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backgroundView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tableView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backgroundColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIColor&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;colorWithPatternImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIImage&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;imageNamed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;myFancyBackground.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Setting the &lt;code class=&quot;highlighter-rouge&quot;&gt;backgroundView&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;nil&lt;/code&gt; doesn’t seem to have any ill side effects that I’ve noticed. Hopefully someone can correct me if I’m wrong.&lt;/p&gt;</content><author><name>Chad Johnston</name></author><category term="development" /><category term="ios" /><summary type="html">Set a grouped table's backgroundView to nil to properly show a custom background when in a popover.</summary></entry><entry><title type="html">Open PDF in New Window with Seam</title><link href="/development/2009/10/12/open-pdf-in-new-window-with-seam.html" rel="alternate" type="text/html" title="Open PDF in New Window with Seam" /><published>2009-10-12T00:00:00-06:00</published><updated>2009-10-12T00:00:00-06:00</updated><id>/development/2009/10/12/open-pdf-in-new-window-with-seam</id><content type="html" xml:base="/development/2009/10/12/open-pdf-in-new-window-with-seam.html">&lt;p&gt;For a recent Seam development project, I had the task of creating a PDF report from some user input and displaying the result in a new window.&lt;/p&gt;

&lt;p&gt;Initially, I used a &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;h:commandLink/&amp;gt;&lt;/code&gt; with &lt;code class=&quot;highlighter-rouge&quot;&gt;target=&quot;_blank&quot;&lt;/code&gt;. This worked well until the user entered criteria that failed validation. The new window was still created, and the validation messages were shown in the new window. This was not a good solution, so after some research and experimentation I came up a solution that meets the following criteria:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Validation messages are shown in original window.&lt;/li&gt;
  &lt;li&gt;A new window is not created when there are validation messages.&lt;/li&gt;
  &lt;li&gt;A new window is not created when the entered criteria returns zero (0) results.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-actionclass&quot;&gt;The Action Class&lt;/h3&gt;

&lt;p&gt;For this example, the action class is very simple:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getReportURL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/pdfpopup/reports/reportDisplay.seam&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Getters and setters omitted&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getReportData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reportData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;doSearch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// This is where the work would actually happen&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;reportData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;selectOneValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reportData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Report Row &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reportData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isEmpty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;facesMessages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Report will be empty, not popping up&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I added the &lt;code class=&quot;highlighter-rouge&quot;&gt;getReportURL()&lt;/code&gt; method to the action because there may be occasions where the report URL differs based on criteria. In the application I worked on, we had to support PDF and Excel reports, so the method returned the correct URL.&lt;/p&gt;

&lt;p&gt;The action simply takes the criteria specified on the JSF page and populates a list of results based on that criteria. The PDF generation page will access the list later.&lt;/p&gt;

&lt;h3 id=&quot;the-jsfpage&quot;&gt;The JSF Page&lt;/h3&gt;

&lt;p&gt;The JSF page looks like this:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ui:define&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;body&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CDATA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;showReport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;conversationId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;messages&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reportWin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'#{reportAction.reportURL}'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'?cid='&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;conversationId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reportWin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Could not open the report window. Please disable popup blocking for this website and try again.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ]]&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;h:form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;generateReport&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;s:validateAll&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;h:panelGrid&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;100%&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;columns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;style=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text-align: center; font-weight:bold; font-size: 12px&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;h:outputText&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Report Query&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/h:panelGrid&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;h:panelGrid&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;columns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;border=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;frame=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;style=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;padding-top:30px;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;h:outputLabel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;selectOneValue&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Number of Output Rows&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h:outputLabel&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;h:selectOneMenu&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;selectOneValue&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#{reportAction.selectOneValue}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;required=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;f:selectItem&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemLabel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Zero&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemValue=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;f:selectItem&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemLabel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;One&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemValue=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;f:selectItem&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemLabel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Two&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemValue=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;f:selectItem&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemLabel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Three&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemValue=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;f:selectItem&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemLabel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Four&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;itemValue=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/h:selectOneMenu&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;h:outputLabel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;startDate&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Report Period:&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h:outputLabel&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;h:panelGroup&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;rich:calendar&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;startDate&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enableManualInput=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#{reportAction.startDate}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;showWeeksBar=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;datePattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MM/dd/yyyy&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;immediate=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;required=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;label=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Report Start Date&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;h:outputLabel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;endDate&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;through&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h:outputLabel&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;rich:calendar&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;endDate&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enableManualInput=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#{reportAction.endDate}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;showWeeksBar=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;datePattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MM/dd/yyyy&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;immediate=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;required=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;label=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Report End Date&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/h:panelGroup&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;a4j:commandButton&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;getReportLink&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#{reportAction.doSearch}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Get Report&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;oncomplete=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;showReport('#{conversation.id}')&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
     &lt;span class=&quot;nt&quot;&gt;&amp;lt;/h:panelGrid&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/s:validateAll&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/h:form&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ui:define&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is really the guts of the operation. When the &lt;code class=&quot;highlighter-rouge&quot;&gt;commandButton&lt;/code&gt; is clicked, the &lt;code class=&quot;highlighter-rouge&quot;&gt;doSearch()&lt;/code&gt; method will be executed. Once that call is complete, the &lt;code class=&quot;highlighter-rouge&quot;&gt;oncomplete&lt;/code&gt; handler will be called.&lt;/p&gt;

&lt;p&gt;The page template is configured so that any &lt;code class=&quot;highlighter-rouge&quot;&gt;FacesMessages&lt;/code&gt; will be displayed in an element with id “&lt;code class=&quot;highlighter-rouge&quot;&gt;messages&lt;/code&gt;”. If this element is present, we assume that either a validation error or no data message is being displayed and do not show the PDF. If the element is not present, everything is OK and we open the new window with the URL for the PDF. Note that it’s crucial to pass the conversation ID along so that the data loaded by the action will be visible to the page creating the PDF.&lt;/p&gt;

&lt;h3 id=&quot;the-pdf&quot;&gt;The PDF&lt;/h3&gt;

&lt;p&gt;For completeness, here’s the sample page I’m using to create a PDF:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;p:document&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns:p=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://jboss.com/products/seam/pdf&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns:ui=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://java.sun.com/jsf/facelets&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns:f=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://java.sun.com/jsf/core&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Sample PDF Report&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;f:facet&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p:font&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;size=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;12&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p:header&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;borderWidthTop=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;borderWidthBottom=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.4&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;p:paragraph&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;indentationLeft=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;50&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;REPORT HEADER&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:paragraph&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:header&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p:footer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;borderWidthTop=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;borderColorTop=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;black&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;borderWidthBottom=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt; [&lt;span class=&quot;nt&quot;&gt;&amp;lt;p:pageNumber/&amp;gt;&lt;/span&gt;] &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:footer&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:font&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/f:facet&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ui:repeat&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;var=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;item&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#{reportAction.reportData}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p:font&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;size=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;8&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p:table&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;columns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;headerRows=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;widthPercentage=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;100&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;p:font&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;style=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bold&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;p:cell&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;verticalAlignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bottom&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Report Data&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:cell&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:font&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;p:cell&amp;gt;&lt;/span&gt;#{item}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:cell&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:table&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:font&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ui:repeat&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p:document&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;full-samplecode&quot;&gt;Full Sample Code&lt;/h3&gt;

&lt;p&gt;You can view and download the full sample code for this solution from &lt;a href=&quot;https://github.com/iamthechad/pdfpopup&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content><author><name>Chad Johnston</name></author><category term="development" /><category term="seam" /><summary type="html">A simple method to open PDFs in a new window while displaying validation errors in the original window.</summary></entry><entry><title type="html">The Phone Screen Works Both Ways</title><link href="/business/2009/09/08/the-phone-screen-works-both-ways.html" rel="alternate" type="text/html" title="The Phone Screen Works Both Ways" /><published>2009-09-08T00:00:00-06:00</published><updated>2009-09-08T00:00:00-06:00</updated><id>/business/2009/09/08/the-phone-screen-works-both-ways</id><content type="html" xml:base="/business/2009/09/08/the-phone-screen-works-both-ways.html">&lt;p&gt;I recently applied for a position through a recruiting service. I jumped through the requisite hoops and was told that the prospective employer was very excited to talk to me.&lt;/p&gt;

&lt;p&gt;The standard procedure for this employer is to give candidates a simple phone screen before arranging an interview. Personally, I feel that having one person make a decision about whether or not I’ll “fit well with the team” after 10 minutes on the phone is ludicrous, but that’s the game I had to play.&lt;/p&gt;

&lt;p&gt;During the phone call, I was asked several generic questions about Java. I gave what I felt was correct answers to the questions, but the interviewer wasn’t happy with my results. Every time I answered a question, I heard “Well, I was looking for…”, with the expected answer simply being a different wording of what I had said.&lt;/p&gt;

&lt;p&gt;I chalked this up to the interviewer simply being used to different terminology than I for the same concepts, so I was a bit surprised when I wasn’t called in for an in-person interview. It wasn’t until a few days later that I realized that the answers I was expected to give told me quite a bit about the company, and that I wouldn’t have been happy working there had I been offered the job.&lt;/p&gt;

&lt;p&gt;The particular question that stuck in my mind was a simple one. “What are some of the benefits of the introduction of generics in Java, especially in collections?”&lt;/p&gt;

&lt;p&gt;I gave the answer that pretty much anybody familiar with Java generics would give: compile-time type checking, no need for casting objects, etc. What I got from the interviewer was “Well, I was looking for the fact that you don’t have to do &lt;code class=&quot;highlighter-rouge&quot;&gt;instanceof&lt;/code&gt; checks all over any more.”&lt;/p&gt;

&lt;p&gt;On the surface, this may seem like another way of saying what I said, but it’s actually quite different.&lt;/p&gt;

&lt;p&gt;Before generics, you would need to cast objects to the proper class when retrieving them from a collection. This does not mean that you would be using &lt;code class=&quot;highlighter-rouge&quot;&gt;instanceof&lt;/code&gt; to do this. The only situation I can think of that requires using &lt;code class=&quot;highlighter-rouge&quot;&gt;instanceof&lt;/code&gt; with a collection is if there are a lot of heterogenous objects in the collection.&lt;/p&gt;

&lt;p&gt;There are limited situations where storing different object types in the same collection makes sense. Most of the time, however, this is a sign of either lazy development or not understanding the collection mechanism very well.&lt;/p&gt;

&lt;p&gt;It’s generally a good idea to only put one type of object into a collection. This makes it much easier to work with and avoids any need for &lt;code class=&quot;highlighter-rouge&quot;&gt;instanceof&lt;/code&gt; checks. By “one type of object”, I don’t mean that all of the objects need to be the exact same class. Chances are good that all of the objects being placed into a collection have some relationship; perhaps they will all implement the same interface.&lt;/p&gt;

&lt;p&gt;I may have completely misinterpreted the interviewer, but I have a very strong impression that he and perhaps others on his team are used to using collections as grab bags of widely different things. Personally, I wouldn’t want to maintain that code. I can hope that the addition of generics to Java has forced the interviewer to change at least one practice for the better. I’m glad I wasn’t called in for the job — who knows how many more “well, at least it works” practices are being followed? I’ve got enough of those at my current job; I don’t need to learn a new set.&lt;/p&gt;</content><author><name>Chad Johnston</name></author><category term="business" /><category term="work" /><summary type="html">A phone screen is typically used to screen applicants for a job, but it gave me enough information to not want to work for the company.</summary></entry></feed>