Matt RaibleMatt Raible is a writer with a passion for software. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

Web Application Testing with Selenium at Agile Denver next Monday

Next Monday evening, Jason Huggins will be in Denver to talk about web application testing with Selenium. Below is an outline of Jason's talk:

  • Overview of Selenium, what it does, what it doesn't do
  • How to get started with Selenium IDE, RC, and Grid
  • Why I started Sauce Labs (Selenium as a Cloud Service)
  • Selenium in 2010... Selenium 2
  • Future trends: Adobe Flex, mobile (iphone/ipad, android), HTML5 (canvas, video)
  • Best practices for succeeding with Selenium

This is an Agile Denver event and I'm really looking forward to it. Prior to Jason's talk (at 6:30), I'll be participating in a panel with several other Denver Testing Experts to discuss Selenium and related topics. This event will be held at the PPA Event Center (directions). We expect a great turnout, so make sure and get there early! For more information, see the meeting announcement.

On a related meetup note, don't forget next Tuesday's Denver Tech Meetup. Last month was a lot of fun and next week's meetup happens to land on Fat Tuesday. I can't think of a good reason not to come. ;-)

If you'd like to RSVP for the Denver Tech Meetup, please do so on LinkedIn or Facebook.

Posted in Java at Feb 11 2010, 08:55:51 AM MST Add a Comment

17" MacBook Pro Stolen from Living Room

Almost 3 years ago, I bought a 17" MacBook Pro. This laptop served me well for several years, mostly as a home computer. A few months after I bought it, I started working at LinkedIn and got a brand new laptop as part of my first day on the job. After working with LinkedIn's 15" for almost 2 years, I grew to love the form factor and purchased another one almost a year ago. I found the 17" was too big for planes and the 15" fits me perfectly.

Fast forward to last night.

I attended the first half of the Ignite talks at DOSUG and left around 7. When I arrived home, I suspected something might be out of whack when my front door was unlocked. Julie had come over to pick up Abbie's dance shoes around 6, so I figured she must've forgot to lock the door on her way out. When I got inside and saw my coat closet open, I justified it by thinking she grabbed one of the kids coats out of the closet and forgot to close the door. When I walked into my living room and saw my space heater's remote in the middle of the floor, busted open with batteries out, it clicked that a stranger was in my house. The first thing that jumped into my head was "Where's my laptop?" As I looked at the bare mini-desk in my living room, I realized it had been stolen.

I called Julie and asked her if she left the front door open. She said no, but when she arrived at my house (and came through the back), the garage's light was on and my back door was wide open. I asked her if she saw the busted remote on the floor or if the closet door was open. She said no. Putting all the pieces together, it appears that the burglar was actually hiding in my closet when Julie came into my house. Naturally, she's a little a freaked out by this, but she also saved the day by scaring off perpetrator before they took anything else.

This isn't a new trend for me and this incident is mostly my fault. I left my backdoor unlocked. Two years ago, my truck's stereo was stolen and there's a good chance I left the doors unlocked (and didn't turn on the alarm). Last year, my bike was stolen and the lock was still there, indicating I missed the frame when locking it up. So getting robbed in the first part of every year seems somewhat par for the course.

With my truck's stereo, it worked out well because the rig needed a new stereo. My bike last year? There wasn't any silver lining to that incident, so I made myself earn a new one. With this laptop incident, there is a silver lining in that I've been thinking about getting a 27" iMac for a home computer. Other options include a Mac Pro for my office (and use my laptop for traveling/home use) or a Mac Mini for home and hook it up to my TV with a wireless keyboard and mouse.

The home iMac seems like the best option, but I'd also be interested to hear what others recommend. Of course, I'll be keeping my doors locked from now on. ;-)

Posted in Mac OS X at Feb 03 2010, 09:45:52 AM MST 11 Comments

Using JRebel with IntelliJ IDEA on OS X

Yesterday afternoon, I figured out how to use JRebel with IntelliJ IDEA. I wrote up some AppFuse documentation for it at Using JRebel with IntelliJ IDEA and figured I'd repost it here for those developers using IDEA 9 and Maven.

  1. Download and install IntelliJ IDEA 9 Ultimate Edition (in /Applications on OS X).
  2. Download and install JRebel.
    1. java -jar jrebel-setup.jar
    2. Install the JRebel Plugin for IDEA. Shortcut: File > Settings > Search for plugins and find JRebel.
  3. On OS X, Modify /etc/launchd.conf and add the following so M2_HOME is available to GUI apps. You'll need to reboot after making this change.
    setenv M2_HOME /opt/tools/maven2
    

    More info on this setting is available on Stack Overflow.

  4. Modify your project's pom.xml to include the JRebel Maven plugin (for generating the configuration of which directories and files to watch for changes).
    <plugin>
        <groupId>org.zeroturnaround</groupId>
        <artifactId>javarebel-maven-plugin</artifactId>
        <version>1.0.5</version>
        <executions>
            <execution>
              <id>generate-rebel-xml</id>
              <phase>process-resources</phase>
              <goals>
                  <goal>generate</goal>
              </goals>
            </execution>
        </executions>
    </plugin>
    
  5. If you're using the Maven Jetty plugin, change your pom.xml so Jetty doesn't reload the app when classes are compiled. Specifically, change scanIntervalSeconds to 0. If you're not using this plugin, you should definitely check it out for Java webapp development.
  6. Use the JRebel icons to start jetty:run in your IDE. JRebel with IntelliJ IDEA
  7. Command Line Integration: Set a JREBEL_HOME environment variable that points to your JRebel install (/Applications/ZeroTurnaround/JRebel on OS X) and set your MAVEN_OPTS to use JRebel's settings. For example:
    export JAVA_OPTS="-Xmx512M -XX:PermSize=256m -XX:MaxPermSize=512m -Djava.awt.headless=true"
    export JREBEL_HOME=/Applications/ZeroTurnaround/JRebel 
    export MAVEN_OPTS="$JAVA_OPTS -noverify -javaagent:$JREBEL_HOME/jrebel.jar"
    

After making these changes, you should able to compile classes in IDEA and refresh your browser. Log messages like the following should show up in your console.

JRebel: Reloading class 'org.appfuse.webapp.action.UserAction'.

To simplify things further, you can map Command+S to compile (instead of Shift+F9). Just look for Keymaps in Settings, rename the default one and search for Compile to remap.

I'm assuming the steps to make things work on Windows and Linux are similar. Please let me know if you have any issues with these instructions.

Posted in Java at Feb 02 2010, 10:34:08 AM MST 3 Comments

Reviews for Grails: A Quick-Start Guide and Kanban and Scrum

A couple weeks ago, I had a business trip from Denver to Washington, DC. Since I didn't have any coding to do on the flight, I brought along a couple books and was surprisingly able to finish them both en route. Tech books that can be read in a single flight are my favorite. Another book I recall doing this with was First Steps in Flex back in December.

The books I read were Dave Klein's Grails: A Quick-Start Guide and Henrik Kniberg and Mattias Skarin's Kanban and Scrum minibook. Below are short reviews of each book.

Grails: A Quick-Start Guide
I've developed a few Grails applications, so I didn't expect to learn a whole lot from this book, but I was pleasantly surprised. Not only did it introduce all the basic concepts in a clear and concise way, it actually made it fun to read. The first chapter does a good job of introducing Groovy; showing you how to use closures and the easy-to-use collections API. From there, you dive into learning about the project, which is actually a real-life web application called TekDays.com. Then the foundational Iteration Zero is planned and executed.

In Chapter 3, you dive right into creating domain classes and their relationships. All the different mapping types are covered: one-to-one, one-to-many and the good ol' many-to-many. Since this is often a difficult part of an application, it's always nice to see how much Grails simplifies it. I liked the Ajax section in Chapter 7 and especially the part where it showed how to do a TagLib to show threaded comments in a forum.

Chapter 7 (Security) was a little disappointing in that it showed how to hand-roll your own security rather than using the Spring Security plugin (formerly Acegi) or the Shiro plugin (formerly JSecurity). I'd especially have liked to see how to do Ajax authentication where a token is generated for the client and included as a header in each subsequent request.

Other than that, I really enjoyed Chapter 10 where I learned how to implement search using dynamic finders, Hibernate's Criteria API and the Searchable Plugin (which gets its awesomeness from Compass). Implementing Compass in Java requires many, many annotations. In Grails, it's as simple as adding the following to your domain class.

static searchable = true

I truly enjoyed this book, especially with its Agile Development patterns that used iterations to get things done. Grails: A Quick-Start Guide is a code-intensive journey that gets up you to speed on Grails quickly and efficiently. It's very much like the framework itself. It eliminates the yak shaving and allows you learn without distractions. Kudos to Dave Klein for creating such an enjoyable and easy-to-read book.

Kanban and Scrum
In my career, I've used Scrum on quite a few projects. Of course, it's not the processes that typically make a team successful. Rather, it's often the gelling of the team members, as well as respect for coding practices that are proven to create higher quality code - specifically TDD and pair programming. Before reading this book, I'd heard a bit about Kanban, most of it from Marty Haught's Lean Teams: Doing more with less presentation.

This book did a great job of showing the differences between the two approaches: how Scrum promotes iterations whereas Kanban promotes cycle time. The most interesting part of the book is the Case Study in the 2nd half. This section shows how a team used various techniques to develop a well-oiled development machine. I think the most important thing to note from this section is how the team was willing to change, learn and grow based on their experiences - in a very rapid fashion.

In my current gig, I'm helping a team of developers move from waterfall to agile processes. We're leveraging many aspects of Scrum and agile by using a coach, iterations, daily standups, TDD, continuous integration and creating "as built" documentation when we finish developing a feature. The "As Built" documentation is something I picked up from working at Chordiant and I've found it to be a great way of education developers (and outsiders) how things were done in an iteration.

One thing we've seen in our first few weeks is that iterations don't work for all teams or individuals. A Kanban model fits much better for them. Having a Kanban board allows them to visualize (and control) their workload in a much more efficient manner. We haven't started implementing actual boards on a wall, we're just using spreadsheets for now. However, we do have two Agile Coaches starting this week so I expect things to improve rapidly.

Back to the book. More than anything, I enjoyed reading this book because it made me excited about the changes I'm helping implement and I believe in many of the practices in both Scrum and Kanban. I enjoy iterations and structured expectations around development, but I can see how Kanban would work better for folks in operations and infrastructure. I look forward to implementing the best parts of both worlds and hopefully a similar Case Study of what worked and what didn't. With any luck, we'll be able to learn, evolve and produce at a much higher level than previous waterfall practices achieved.

Posted in Java at Feb 01 2010, 09:29:40 AM MST 5 Comments

Upside Down Man Saves the Day

Yesterday, Abbie and Jack showed you how to be a superhero. Today they're back with an action-packed video titled Upside Down Man Saves the Day. Watch it if you'd like to see how to take out a tiger, wrestle an alligator and diffuse a bomb. This short film was written, directed and filmed by Abbie, the only thing I did was add the music. Enjoy! ;-)

If you have trouble viewing it here, check it out on YouTube.

Posted in General at Jan 31 2010, 04:54:31 PM MST 1 Comment

How to be a Super Hero by Abbie and Jack

For some reason, my kids are very interested in Super Heros lately. In fact, they know so much about them that they've decided to start teaching others how to become one. Checkout the videos we shot earlier today with their step-by-step instructions.

I hope Abbie and Jack's tips help you become a super hero! :-)

Posted in General at Jan 30 2010, 04:42:29 PM MST 6 Comments

What's your preferred development infrastructure stack?

Over the years, I've used many different source control systems, wikis, bug trackers and continuous integration servers. On many projects, I've been responsible for recommending and helping to install these systems. For the most part, they've often been disparate, meaning there wasn't a whole lot of integration between the various applications. Here's a list of all the different systems I've used:

I believe all of these applications are useful in supporting an efficient development process. When clients have asked me to help them build this type of infrastructure, I've often asked if they wanted to pay for it or not. If not, I'd recommend Trac (since it has a wiki, source viewer and bug tracker all-in-one) and Hudson. If they were willing to pay, I'd recommend the Atlassian Suite (Confluence, JIRA and Bamboo).

These stacks all seem to work pretty well and the Atlassian Suite certainly works great for AppFuse and other open source projects. However, I recently had the pleasure of working at Chordiant Software where we used Chordiant Mesh to collaborate and develop software. Their Mesh system is powered by Jive Clearspace and provides a wealth of tools for each project, including a dashboard, discussions, documents, notifications and widgets providing status + links to JIRA and Bamboo.

Even though Clearspace's rich text editor caused me some early frustration, I really enjoyed the fact that a solid development infrastructure existed. It made it much easier to collaborate, document and execute our development process. I realize that it's difficult to build and maintain a custom development infrastructure stack. Chordiant had a whole team that developed, enhanced and supported their environment. But that doesn't mean it's impossible and not worth striving for.

I think there's a number of best-of-breed applications you can use to build a sweet development infrastructure stack.

  • Source Control: Git
  • Source Viewer: FishEye
  • Wiki: Jive SBS
  • Bug Tracker: JIRA
  • Continuous Integration: Hudson

I've only used Git for a few weeks, but I can easily tell it's better than Subversion. I don't think it's easy to convince companies to switch their source control system, so it's probably not worth arguing if you're already using Subversion. I can also envision using Confluence instead of Jive SBS, but then you lose forum support and have to use something like Mailman or Google Groups. JIRA Studio looks close to my dream stack, except it doesn't support Git or a forum + mailing list system.

What is your preferred development infrastructure stack? Why?

Posted in Java at Jan 12 2010, 09:54:46 PM MST 30 Comments

2009 - A Year in Review

I wrote my first "year in review" post in 2005 and continued the tradition in 2006 and 2008. This year, my December was filled with unplanned circumstances, a new job and a houseful of family for the holidays, so I never had time to sit down and write this post. As things are returning to normal, I figured it's about time I kicked off 2010 with one of my favorite writing reflections.

Experts Only 2009 started off with a bang: I wrote about my Mom nailing a bear's nuts to a tree after she killed it. My new gig (at Evite) started out fun with choosing an Ajax framework and a Tech Meetup in LA. My bike got stolen, I started running to work and traveled to Tahoe without an ID.

February started off with an epic weekend at Silverton. I went to Web Directions North and attended many good talks:

I wrote my first GWT-related entry and a few posts related to independent consulting.

I ended February with a couple more GWT-related entries.

On the top In March, I bought a new 15" MacBook Pro and shipped it back shortly after to get a 256 GB SSD. I still have nothing but good things to say about the machine. I discovered Nexus is awesome and the kids and I went on our first hike of the year.

My GWT Journey continued with GXT MVC, modularization and optimization. I got a new office and new bike and proudly witnessed my Dad's Retirement.

April came and I got Drunk on Software, had a blast at Holly and Jason's Wedding and published our Ajax Framework Analysis Results.

Mr. and Mrs. Harris

At the end of April, I started building the kids a treehouse and inspired smiles with two new kittens. On May 7th, I had PRK eye surgery and wrote about my experience in early June. I continue to be extremely happy with the results.

Day 3 - They love it! Day 4 - Floor completed Jack and Olivia Abbie and Mittens

May ended with Ryan and Breanne's Wedding in Playa Del Carmen. Having so many great friends around and the Nuggets vs. Lakers playoffs the same week made this one of the best vacations of my life.

Ready for the Ceremony Vows Mariachi Band Mr. and Mrs. Johnson

June brought the news that the Colorado Software Summit was over. There's been several times in the past few months that I've missed the annual experience. Can someone please start a conference at a Colorado mountain resort in the near future? Pretty please! I've always experienced this conference with Bruce and we continued another tradition (riding to Red Rocks) with 2nd Row seats at Big Head Todd.

My GWT posts continued with a Facebook-style Autocomplete, Implementing OAuth, JSON Parsing with JavaScript Overlays and a preview of GWT 2.0. I wrote about implementing SOFEA with GWT and Grails at Evite.com and had a blast at the Great Sand Dunes on Father's Day.

Abbie and Cookie at The Dunes

My job hunt began and I started a month-long vacation in Montana with Raible Road Trip #13. Vacationing for a summer month in Montana has been one of my goals for several years. Accomplishing it this year made me extremely happy and I hope to make it a summer tradition.

July was an awesome month in 2009. Granted, April and May were special with tropical weddings, but Montana in July is a particularly tasty treat. My Summer Vacation in Montana attempts to capture how much fun we had. It was particularly enjoyable because my parents, children and many life-long friends were involved.

View of the Missions from Holland Falls Ready for the Celebrate the Swan Race Horseshoes Floor Pouring Crew

As summer began to set, I decided to get back into speaking at conferences, starting with the Rich Web Experience. I wrote about initial GWT work at my new client, which included an interesting experience with Java REST Frameworks. The month ended with one of my favorite holidays: Jack's Birthday.

September was nice and uneventful. I learned about Concurrency on the JVM Using Scala, started using MVP with GWT and learned how to do more with less. I also ran in a 10K.

October started out with a family trip to Washington for my sister's fabulous wedding. People flew in from all over the US and we had a sweet condo on Lake Chelan for the week. Playing golf, wine tasting and celebrating with good people made for a great start to the fall season.

Kalin and Mya

Abbie and Charles In November, I started writing more, mostly because I was gearing up for upcoming talks and thinking about / working on AppFuse. I celebrated Abbie's Birthday, did some website optimization and chuckled at the comments about my hunting season adventure.

Right before Thanksgiving, I got a call from my client letting me know that their budget had run out my contract would end soon. Luckily, I had an interview setup the next day and had great success in finding a new gig.

I ended November with a trip to Oregon for Thanksgiving and ran in the Oregon Mid-Valley Road Race. The followed week, I flew with my kids and parents to The Rich Web Experience and learned about Objective-J and Cappuccino. I had a near-perfect (high 70s, no lines) Disney World experience with my family, watched the Ducks with the Civil War and compared kick-ass web frameworks.

Kids at Loews Portofino, Universal Studios Florida

In December, I didn't do much blogging - mostly because I arrived home from Florida to discover a waterfall in my guest room. The water pipes were routed through the ceiling, had busted from the cold, and water was pouring everywhere. Dealing with that and starting a new job occupied most of my time and I never got a chance to write much down. I ran in the Jingle Bell 5K and watched the Broncos lose a lot. Shortly after, my family came for Christmas and a good time was had by all.

As I reflect back on last year, my biggest surprise is that I got into running. I ended up running in 5 races last year and even enjoyed doing it a few times. It's still not my favorite activity (skiing and mountain biking win that title), but I enjoy it enough to do it a couple times each week. The goals I wrote down for last year were: visit 3 foreign countries, take 3 months of vacation and spend 1 month in Montana. I only made it to 1 foreign country (Mexico), but I did take 2 months of vacation and got my month in Montana. I'll take that.

In 2010, I hope to speak at (or attend) 3 conferences, finish up The Bus and do a whole bunch of skiing and mountain biking. More than anything, I plan to continue having a lot of fun with my family and implementing a lot of cool technologies along the way.

It's gonna be a great year.

Posted in Roller at Jan 11 2010, 10:06:09 AM MST Add a Comment

Grails OAuth and LinkedIn APIs

Back in November, I wrote about how to talk to LinkedIn APIs with GWT. A week later, I figured out how to do it with Grails and contributed a patch to the grails-oauth plugin.

Since then, a few folks have asked how I did it. Since code speaks louder than words, I took some time and 1) verified the oauth plugin works as expected and 2) created an example application demonstrating functionality. You can find the results in my fork of grails-oauth on GitHub. You can also view the example online.

Below is a quick tutorial explaining how to integrate LinkedIn into your Grails application.

  1. Download and install Grails 1.1.2.
  2. Run grails create-app to create your application.
  3. Add the following to the bottom of grails-app/conf/Config.groovy:
    oauth {
        linkedin {
            requestTokenUrl="https://api.linkedin.com/uas/oauth/requestToken"
            accessTokenUrl="https://api.linkedin.com/uas/oauth/accessToken"
            authUrl="https://api.linkedin.com/uas/oauth/authorize"
            consumer.key="XXX"
            consumer.secret="XXX"
        }
    }
    
    You can get your consumer.key and consumer.secret at https://www.linkedin.com/secure/developer. Make sure to set the OAuth Redirect URL to http://localhost:8080/{your.app.name}/oauth/callback for testing.
  4. Download the oauth-plugin, extract it and build it using grails package-plugin. Install it in your project using grails install-plugin path/to/zip.
  5. Add a link to the GSP you want to invoke LinkedIn Authentication from:
    <g:oauthLink consumer='linkedin' returnTo="[controller:'profile']">
        Login with LinkedIn
    </g:oauthLink>
    
  6. Create grails-app/controllers/ProfileController.groovy to access your LinkedIn Profile.
    class ProfileController {
        def apiUrl = "http://api.linkedin.com/v1/people/~"
        def oauthService
        
        def index = {
     
            if (session.oauthToken == null) {
                redirect(uri:"/")
            }
     
            if (params?.apiUrl) apiUrl = params.apiUrl
            
            def response = oauthService.accessResource(
                    apiUrl, 'linkedin', [key:session.oauthToken.key, secret:session.oauthToken.secret], 'GET')
     
            render(view: 'index', model: [profileXML: response, apiUrl: apiUrl])
        }
     
        def change = {
            if (params?.apiUrl) {
                println("Setting api url to " + params.apiUrl)
                apiUrl = params.apiUrl
            }
            
            redirect(action:index,params:params)
        }
    }
    
  7. Create grails-app/views/profile/index.gsp to display the retrieved profile and allow subsequent API calls.
    <html>
    <head><title>Your Profile</title></head>
    <body>
    <a class="home" href="${createLinkTo(dir:'')}">Home</a>
    <g:hasOauthError>
        <div class="errors">
            <g:renderOauthError/>
        </div>
    </g:hasOauthError>
    
    <g:form url="[action:'change',controller:'profile']" method="get">
        Your LinkedIn Profile:
        <textarea id="payload" style="width: 100%; height: 50%; color: red">${profileXML}</textarea>
        <p>
            <g:textField name="apiUrl" value="${apiUrl}" size="100%"/>
            <br/>
            <g:submitButton name="send" value="Send Request"/>
        </p>
    </g:form>
    </body>
    </html>
    
  8. Start your app using grails run-app and enjoy.

As mentioned earlier, you can download the grails-oauth-example or view it online.

One improvement I'd like to see is to simplify the parsing of XML into a Profile object, much like the linkedin gem does for Rails.

If you're interested in learning more about LinkedIn and OAuth, I encourage you to checkout Taylor Singletary's presentation LinkedIn OAuth: Zero to Hero.

Update: I updated the oauth-plugin so it's backwards-compatible with OAuth 1.0 and added Twitter to the example application to prove it. If you're seeing "Cannot invoke method remove() on null object", it's likely caused by your redirect URL pointing to an application on a different domain.

Posted in Java at Dec 22 2009, 03:37:57 PM MST 7 Comments

Comparing Kick-Ass Web Frameworks at The Rich Web Experience

Yesterday, I delivered my Comparing Kick-Ass Web Frameworks talk at the Rich Web Experience in Orlando, Florida. Below are the slides I used:

Although it's difficult to convey a presentation in a slide deck, I can offer you my conclusion: there is no "best" web framework. I believe web frameworks are like spaghetti sauce in that everyone has different tastes and having so many choices is necessary to satisfy everyone. You can read more about the plural nature of perfection in Malcolm Gladwell's The Ketchup Conundrum (a written version of What we can learn from spaghetti sauce). Even though there is no "best" web framework, I believe GWT, Flex, Rails and Grails are frameworks that every web developer should try. They really do make it fun to develop web applications.

You can find the slides for my other RWE talk at Building SOFEA Applications with GWT and Grails.

Kudos to Jay Zimmerman for putting on a great show in Orlando this year. I had a great time talking with folks and learning in the sessions I attended. I particularly enjoyed bringing my parents and kids and staying at such a nice resort. Disney World (Magic Kingdom) and Universal Studios was very enjoyable due to the short lines. Also, the weather was perfect - especially considering the freezing cold in Denver this week. ;-)

Posted in Java at Dec 04 2009, 08:16:48 AM MST 3 Comments