Sunday, January 31, 2010

CFQUERYPARAM Reuse With QueryRun() in Open BlueDragon

I'm working on an application with a friend of mine and we're taking full advantage of all the great new functions and features in Open BlueDragon. One of the new functions I wasn't sure I'd use all that much is QueryRun(), which lets you run a query in a CFSCRIPT block like this:

<cfscript>
  QueryRun(datasource, sqlStatement, queryParams);
</cfscript>

Let's look at a concrete example. Assume a table called "user" with fields of id, email, first_name, and last_name, and a datasource named "myDSN". To pull all the users, you'd do this:

<cfscript>
  getUsersSQL = "SELECT id, email, first_name, last_name FROM user";
  users = QueryRun("myDSN", getUsersSQL);
</cfscript>

Now if you want to pull a specific user--let's say by email--you can parameterize your queries by using an array of structs that represent the CFQUERYPARAM tags, where the key in each struct is the attribute name from CFQUERYPARAM, and the value for each key is the value of the CFQUERYPARAM attribute. Things start looking a bit Java-esque with the question marks, but here's how that works (and note use of the newly added implicit array and struct notation):

<cfscript>
  getUsersSQLParams = [{value = "matt@mattwoodward.com", cfsqltype = "cf_sql_varchar", maxlength = 100}];
  getUsersSQL = "SELECT id, email, first_name, last_name FROM user ";
  getUsersSQL &= "WHERE email = ?";
  users = QueryRun("myDSN", getUsersSQL, getUsersSQLParams);
</cfscript>

Let's go over what's going on here. First, in the struct contained in the getUsersSQLParams array, you can see the familiar attributes of value, cfsqltype, and maxlength from CFQUERYPARAM. Next, notice the ? in the SQL statement. Any question marks in your SQL statement will get replaced in the order in which they appear by the structs contained in the SQL parameters array. So in this case, that ? in the SQL statement essentially becomes a CFQUERYPARAM with the key/value pairs in the struct defined two lines above.

To reinforce this point, let's look at an example pulling a user by first name and last name:

<cfscript>
  getUsersSQLParams = [{value = "Matt", cfsqltype = "cf_sql_varchar", maxlength = 100},
                    {value = "Woodward", cfsqltype="cf_sql_varchar", maxlength = 100}];
  getUsersSQL = "SELECT id, email, first_name, last_name FROM user ";
  getUsersSQL &= "WHERE first_name = ? AND last_name = ?";
  users = QueryRun("myDSN", getUsersSQL, getUsersSQLParams);
</cfscript>

In that case I have two parameters in my SQL statement represented by two question marks, the first of which is replaced by the first struct in the SQL parameters array (corresponding to first_name), and the second is replaced by the second struct in the array (corresponding to last_name).

While working on this application I came across an added bonus with this way of doing things that I didn't really consider when the feature was first added to Open BlueDragon. Since your query parameters are stored in an array of structs as opposed to being added to each query as individual CFQUERYPARAM tags, you can re-use the query parameters across multiple queries.

When would this come in handy? Consider basic CRUD operations, specifically inserts and updates. In many cases the only difference between an insert and update is a "WHERE id = ?" clause, but using CFQUERY you wind up having to repeat a ton of CFQUERYPARAM tags between the two queries.

By using QueryRun() and the array of structs that represent the query parameters, these parameters can be reused between an insert and an update operation. This example is fairly trivial since the table is so small, but you can imagine how much redundancy you save on large tables.

<cffunction name="save" access="public" output="false" returntype="void">

  <cfargument name="user" type="User" required="true" />

  <cfscript>
    var commonSQLParams = [{value = arguments.user.getEmail(), cfsqltype = "cf_sql_varchar", maxlength = 100},
                           {value = arguments.user.getFirstName(), cfsqltype = "cf_sql_varchar", maxlength = 100},
                           {value = arguments.user.getLastName(), cfsqltype = "cf_sql_varchar", maxlength = 100}];

    // if the ID is 0 do an insert, otherwise do an update
    if (arguments.user.getID() == 0) {
      var insertUserSQL = "INSERT INTO user (email, first_name, last_name) ";
          insertUserSQL &= "VALUES (?, ?, ?)";
      var insertUser = QueryRun("myDSN", insertUserSQL, commonSQLParams);
    } else {
      ArrayAppend(commonSQLParams, {value = arguments.user.getID(), cfsqltype = "cf_sql_integer"});
      var updateUserSQL = "UPDATE user SET email = ?, first_name = ?, last_name = ? ";
          updateUserSQL &= "WHERE id = ?";
      var updateUser = QueryRun("myDSN", updateUserSQL, commonSQLParams);
    }
  </cfscript>
</cffunction>

Since the update statement only needed the one additional WHERE parameter of the ID, I can just append that to the end of the SQL parameters array I created from the data in the user object and re-use the rest of the parameters for both queries.

Personally I think that's pretty darn slick, and although at first the ? notation may seem a bit odd at first (at least if you aren't used to doing things that way in Java), you wind up with some very concise code when using QueryRun() due to the ability to reuse the SQL parameters across multiple queries.

Friday, January 29, 2010

Implicit Array/Struct Creation and new Operators in Open BlueDragon


Today sees the release of some much awaited support for both implicit array/struct creation and a whole host of operators. The cfscript and expression parsing engines have been rewritten, switching from the javacc based parsers to a cleaner and leaner ANTLR based one.



Check out all the details on the OpenBD blog!

Thursday, January 28, 2010

In Seattle? Into Groovy and Grails? Join the Seattle Groovy/Grails Meetup!

If you're in the Seattle area and interested in Groovy and Grails, make sure and join us at next month's Seattle Groovy/Grails Meetup on February 11. We get together every month at the Elephant & Castle, and it's a casual mix of Groovy, Grails, other technology, and whatever else comes up.

All are welcome so even if you're not using Groovy and Grails yet, come join us and we can all learn from each other. See you there!

Running ColdFusion Under a Service Account on Windows Server and Null Pointer Errors

I was installing ColdFusion 8.01 on a new Windows Server 2003 VM yesterday, and since the application that will be running on this box needs access to network shares I had our network admins create a new domain service account under which to run ColdFusion. This is pretty commonplace for a lot of our apps, but for some reason when I switched the CF service to run under the service account I started getting a 500 error with the following details when any .cfm page was hit:


 



java.lang.NullPointerExceptionat jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:285)at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)



This was even after I had assigned "full control" rights to the service account user to the application directory.


I asked around a bit since I'd never seen this before, and Dave Watts came up with the solution. (Thanks Dave!) In this case I logged onto the server via remote desktop using the service account, at which point I was forced to change my password. After I changed my password, the remote desktop login didn't proceed because that user didn't have RDP rights on the server. I didn't think that was an issue, but Dave suggested that there might be a problem if the service account didn't have a local profile created on the server, which of course happens the first time a user logs in.

I gave the service account RDP rights, logged in as that user, the local profile was created, and everything works now. So if you see null pointer errors when trying to run CF using a service account, this might be your problem.

Wednesday, January 27, 2010

Remember Kids, IE Security Settings Affect Firefox Too

I was configuring a new Windows Server VM yesterday, and the first thing I do on a blank Windows server is launch IE once and once only to download Firefox. To avoid what I call the "trusted site dance" with Mozilla's mirrors since IE doesn't let you add a trusted site and then continue the download you started, I go into IE security settings and make the following setting changes to the Internet zone:
  • Enable file downloads
  • "Prompt" for launching applications and unsafe files
  • "Prompt" for launching programs and files in an IFRAME
Note that these are the settings you need to change if you get the "Your current security settings do not allow this file to be downloaded" error.

This time I decided to be a good boy and change these settings back to disabled after I was done, and then I launched Firefox to download Java and some other things I need to install on this server. This probably shouldn't have surprised me, but when I tried to download anything in Firefox, it would download a 0 byte file and the download dialog box would read "Canceled."

I went back into IE's security options and re-enabled file downloads and voila, I could download files again.

I understand the fact that IE's security settings tab is really a shortcut for Internet Options at the OS level, but this is still pretty irritating. What if I want file downloads disabled for IE but enabled for Firefox? Guess you can't do that. Thanks Windows.

Tuesday, January 26, 2010

Tom Shales - In dying color: No. 4 NBC has cast itself in the role of the fading peacock - washingtonpost.com


Might the trademark "NBC" be retired and the TV network become just another cog in a large, empty capitalist apparatus -- one that plops out leisure-time product with the slick, chilly efficiency of an assembly line? It's possible that Comcast could be even more tightfisted an owner than GE and that NBC might be the first network to prove that the whole idea of broadcast networks really is over. It could prove it by dying.



One of the networks has to be the first to go, and the most likely candidate is NBC. I was watching "Modern Family" the other night and one of the storylines (if you can call it that on a 22-minute sitcom) was about how no one in the house other than the Dad knows how to use the remote. (Tired gag, but well done in this case.)

So Dad is trying to convince Daughter to let him teacher her how to use the remote to show up Mom who says no one can learn it. Daughter exclaims, "Dad, this is stupid. I watch TV on my computer! Why do I have to learn this?"

It was said in passing but I think that pretty much sums up the future. People like myself who watch TV on the network's schedule, even when you take DVRs into account, are a dying breed and so are the networks. I think my eyes will be really opened up to this when my Moxi arrives this week and I hook it into PlayOn. Even if I watch TV shows being served *from* a computer I don't really enjoy watching them *on* a computer. ;-)

Comparing Two Arrays in CFML

This came up yesterday in a discussion with a friend of mine. He had two arrays and he wanted to see if they were identical in terms of order and value of the elements. His first thought was to loop through the arrays and compare each element, but since CFML arrays are really Java arrays, there's a much simpler way.

<cfscript>
arrray1 = ArrayNew(1);
array1[1] = "foo";
array1[2] = "bar";

array2 = ArrayNew(1);
array2[1] = "foo";
array2[2] = "bar";


arraysAreEqual = array1.equals(array2);
</cfscript>

The equals() method on the array returns a boolean and tells you whether or not the arrays are identical in terms of the values and ordering of the array elements. Note that if the values are identical but in a different order, the arrays will not be considered equal, so sort before doing this test if there's a chance things might be in a different order between the two arrays.

Thursday, January 21, 2010

YouTube Blog: Introducing YouTube HTML5 Supported Videos


A while ago, YouTube launched a simple demo of an HTML5-based video player. Recently, we published a blog post on our pre-spring cleaning effort and your number one request was that YouTube do more with HTML5. Today, we're introducing an experimental version of an HTML5-supported player.

HTML5 is a new web standard that is gaining popularity rapidly and adds many new features to your web experience. Most notably for YouTube users, HTML5 includes support for video and audio playback. This means that users with an HTML5 compatible browser, and support for the proper audio and video codecs can watch a video without needing to download a browser plugin.




Two words: Freakin'. Awesome. I probably wouldn't care so much if Flash didn't suck such copious amounts of ass on 64-bit Linux, but I can't wait to give this a shot.

Apache Releases Tomcat 6.0.24 – What's New


The new stable release of Tomcat 6.0.24 represents six months of open source software development. Version 6.0.24 includes a small number of new features, plus a large amount of important bug fixes and enhancements. This release is an incremental bug fix release, but the number of fixes included in this release is high.



Some very nice stuff in Tomcat 6.0.24, particularly surrounding memory leak handling. I haven't run into issues with memory leaks on 6.0.20 in my own applications, but they did a lot of work in that area.

And a biggie--a native installer for 64-bit Windows. Halle-freakin'-lujah! No more grabbing the exes from SVN and overwriting the ones that come with the 32-bit installer.

Guest Column: On TSA Laptop Searches | GamePolitics


Domestic travelers have become familiar with intrusions and searches at Transportation Security Administration security checkpoints. But as the ACLU has recently discovered, international travelers are not only having their laptops seized and searched by Customs and Border Protection, but agents are making copies of files and giving them to third-party agencies. The ACLU filed a Freedom of Information Act lawsuit against the government, which turned over hundreds of pages of documents revealing startling information about how much access—and how little oversight—agents have to your gaming laptops when you travel.



I'm not quite sure why this is even remotely acceptable in a free society. Maybe I'm being naive, but from a legal standpoint why can't people simply say "hell no" if some jackass from the TSA starts copying files from your hard drive to give to a third party? Have we really lost this much freedom?

Wednesday, January 20, 2010

Componentix blog - Run long batch processing jobs in Grails without memory leaks


In one of our Grails applications we had to run a number of batch jobs. Nothing unusual and Grails supports it quite well with the excellent Quartz plugin.

But when we deployed application in production, we noticed that after running for some time, it consumed a lot of memory and JVM was spending all the time running garbage collection. The reason for it was that our jobs were quite long-running, taking several hours to complete, and Grails wasn’t really designed for such kind of use case.




But "not designed for" doesn't mean it's not possible, of course. Great info about how to clear out some of the things that will eat up memory over time in long-running Grails processes.

Tuesday, January 19, 2010

Open Source For America - Proposed Guidelines for Open Government Plans


Open
Source for America (OSFA) represents more than 1,500 businesses,
associations, non-governmental organizations, communities, and
academic/research institutions who have come together to support and
guide federal efforts to make the U.S. Government more open through the
use of free and open source software.



I'm beyond pleased to see this taking shape. You can hit the link above and contribute to the discussion. The open government initiative should be based on open source software wherever possible, otherwise it falls short.

Saturday, January 16, 2010

OpenBD gets native JSONP support


However, what if you wish your services to be consumed by a Javascript function outside of your own domain? Cross-domain scripting will prevent this. So how do the likes of delicious.com offer such Javascript integrations for their services?



You achieve this by using JSONP (JSON with Padding) and this lets you achieve cross-domain data fetching.



JSONP requires a little assistance from both the server and the client inorder for it to work. JSONP works by wrapping the returning JSON packet in () and prepending a name to make it into a Javascript document.



The majority of Javascript libraries support JSON from their native core. JQuery supports it using $.getJSON method, which simply asks that you append the URI parameter "callback=?" to the end of the remote URL and it will do all the marshalling of data for you.




Another extremely slick addition to OpenBD! It's available in the nightly build. Read more at the full blog post (link above).

Friday, January 15, 2010

Twitter Plugin for Open BlueDragon

I finally got a chance to put some time in on a Twitter plugin for Open BlueDragon, and I'm happy to report it's coming along very nicely! The plugin API for OpenBD is really easy to dig into so I thought a Twitter plugin would be as good an exercise as any to get my feet wet. I'm planning a series of blog posts illustrating how to write plugins for OpenBD using the Twitter plugin as an example, so look for that before long.

If you aren't familiar with the plugin API for OpenBD, this is a really slick way for you to add tags and functions to OpenBD that become available natively within your OpenBD instance. The plugin code is written in Java (don't worry, it's not daunting at all), and you then drop a JAR file into your WEB-INF/lib directory. When OpenBD fires up it detects the plugin, registers the functions and tags contained within the plugin, and they're then available for you to use in your CFML code.

You can learn more about the plugin API on the OpenBD wiki, and Alan Williamson also has a great blog post about it. Note that you can do much more than add tags and functions; you can also listen for events occurring inside OpenBD itself and act on these events, and even call CFCs from within your plugin. Very powerful stuff. OpenBD ships with a plugin for IRC, and spreadsheet, wiki, and JavaScript plugins are also implemented via the plugin architecture, and they're available on the OpenBD download page.

But I digress. ;-) The main reason for this post is to give people an overview of how the Twitter plugin is working thus far, but more importantly to ask for your help. Creating a Twitter object with a TwitterNew() function and subsequently calling methods on that was really easy, but of course we CFMLers love our tags, so I also created a CFTWITTER tag. What I don't want to do, however, is add an ACTION attribute to the CFTWITTER tag for every method available on the object, so if people have thoughts on how they'd like the tag to work I'd love some opinions.

So what can you DO with the Twitter plugin for OpenBD? Well, pretty much anything you can do with the Twitter API. Basically I took the excellent jTwitter Java library and rolled that in the OpenBD plugin, and this exposes Twitter functionality natively to CFML. Here's some examples.

<!--- create a new twitter object --->
<cfset myTwitter = TwitterNew('username', 'password') />

<!--- get your friends timeline --->
<cfset timeline = myTwitter.getFriendsTimeline() />

<!--- set your status --->
<cfset status = myTwitter.setStatus("Hello from OpenBD!") />

<!--- search twitter --->
<cfset searchResults = myTwitter.search("openbd") />

You get the idea. I've implemented all the methods listed in the jTwitter javadocs, but I'll have documentation for the plugin when I make it available to download. (And hey, if you're a really, really early adopter, email me and I'll send you a copy!)

As for the tags, this is where I need your help. To me it makes complete sense to do this:

<cftwitter action="login"
               screenname="foo"
               password="bar"
               variable="myTwitter" />

But the path I don't think is worthwhile to go down is to start implementing a tag action per method available on the Twitter object, since that gets unnecessarily verbose in my opinion. So I started thinking about having some of the more common things you'd want to do with Twitter available via the tag for convenience, and maybe even let the login and action you want to perform be part of the same single tag. So maybe something like this:

<cftwitter action="setStatus"
               screenname="foo"
               password="bar"
               status="Hello from OpenBD!" />

<cftwitter action="getFriendsTimeline"
               screenname="foo"
               password="bar"
               variable="myTimeline" />

In other words, implement some of the commonly used actions so you can execute these in a single line, but leave the bulk of things available via first instantiating a Twitter object and then calling methods on that. My thinking is if you're going to perform multiple actions it's a lot less verbose to do that with the Twitter object than it is to call a tag each time and pass back in the variable name of the Twitter object on which you want to run the action.

So I'd love to get some opinions on this, and on the idea of a Twitter plugin in general, whether they be good, bad or indifferent.

Wednesday, January 13, 2010

Slashdot Technology Story | YouTube Revamp Imminent?


YouTube's latest blog post indicated that some changes are on the way. Google has opened up a call to submit and vote on ideas. HTML 5 open video with Free formats has dominated the vote, maintaining over twice as many votes as the next-highest item almost since the vote opened up. You may vote here (Google login required).



Really interesting to see the huge number of people who want to see Flash gone from a revamped YouTube. I'd love to see Theora personally.

Software Development: Doing It Scared | Our Blog | Box UK


In software, we are often faced with things that can seem intimidating. We may be assigned a project that we know nothing about. We may have to use a new tool or environment. We may be working with people who can seem intimidating. The natural temptation is to retreat to a place of safety, but that won’t get the job done. So how can we, as software developers, overcome the instinct to cower when projects seem daunting? I’ll go over a few things that have worked for me under these circumstances; your mileage may vary



This is an absolutely fantastic post outlining how to get your lazy self (hey, I'm including myself here) outside your comfort zone. When I first started working with Grails I tweeted something like, "I have no idea what I'm doing and it's a great feeling," and this blog posts captures that same sentiment in a more practical way. I really love the "do it scared" mantra. Words we developers should live by more often than we do.

Multiple Data Sets on Line Charts with Google Chart Plugin for Grails

I'm working on a Grails project and we're using the very slick Google Chart Plugin to handle the charting aspects of the project. If you aren't familiar with the Google Chart API be sure and check it out; even if you aren't using Grails it's a really simple way to add charting to any application. You just call a URL on Google and in return you get a very nice looking chart, and it supports just about any type of chart you can think of. Cool stuff.

One of my tasks today was to get a line chart up and running, and I was having a bit of trouble getting multiple datasets working on a line chart when using two separate Groovy lists. The solution turned out to be simple but since it took a bit of head banging to get there I figured I'd share in case others run into this.

The data I have is simple integers in two Groovy lists (let's call them dataSetA and dataSetB), and in my controller I'm putting the lists in the model for the view so they're already available. Here's the syntax for a simple line chart using the Google Chart Plugin with one data set:

<g:lineChart
    size="[400,300]"
    colors="['00ff00','ff0000']"
    type='lc'
    legend="['Data Set A', 'Data Set B']"
    fill="bg,s,efefef"
    dataType='simple'
    axes="x,y"
    data="${dataSetA}" />

This worked fine. To add a second data set, you simply separate the two data sets with a comma, so you'd think this would work (or at least I did):

<g:lineChart
    size="[400,300]"
    colors="['00ff00','ff0000']"
    type='lc'
    legend="['Data Set A', 'Data Set B']"
    fill="bg,s,efefef"
    dataType='simple'
    axes="x,y"
    data="${dataSetA},${dataSetB}" />

For some reason the lineChart tag doesn't like that syntax. I'll save you the various things I tried to get the data into the right format so I could pass the lineChart tag a single attribute and just give you the solution. Basically you just create a new list using the two existing lists as its elements:

<% def combinedDataSets = [ dataSetA, dataSetB ] %>

<g:lineChart
    size="[400,300]"
    colors="['00ff00','ff0000']"
    type='lc'
    legend="['Data Set A', 'Data Set B']"
    fill="bg,s,efefef"
    dataType='simple'
    axes="x,y"
    data="${combinedDataSets}" />

As I said, very simple fix but it took me a while to get there. Be nice, I'm still kind of new to Grails. ;-)

Hope that helps someone else who may run into this.

Saturday, January 9, 2010

The Switch From iPhone To Android, And Why Your First Impression Is Wrong


A week or so later, it clicked. When I want an option that isn’t already visible, I hit the dedicated ‘Menu’ button just beneath the screen. Need to jump to a previous screen in an app or the web browser? Hit the dedicated ‘Back’ button. In some ways, these are actually better than the soft buttons located in iPhone apps, because they’re always in the same place. It also saves some screen real estate. Using them has become totally second nature to me. But they aren’t the reason why I’ve decided I prefer Android over the iPhone.



First time I've seen someone make this point, and to me this is dead on. Having used my Droid for a while now, when I go back to using apps on my iPod Touch the lack of dedicated, single-purpose buttons is frustrating, and in some cases even within Apple's much-lauded app store, it's easy to box yourself into a corner and have no way to get back to a previous screen. This is because it's up to the app to provide navigation, and in some cases they simply don't.

This whole article is great and it's refreshing not only to see someone stand up and say that Android is actually better (it is), but to examine and explain why long-time iPhone users may find Android off-putting, at least at first.

Cybersafety in Boston -- Lie Flat in a Ditch?



Media_httpimgthedaily_jours




Why did I think of Windows when I read this? ;-)

Pragmatic Dictator » Tech is for Sissies


So often I see companies create job specs for engineers where the key requirement is to hire someone who can hit the deck coding like mad using whatever tools have been selected. To that end they load the specs up with endless tech hubris and at interview ask the details of this or that bit of syntax or API call. But what about the next project within the company where the tech is different? All those engineers that just got hired are now useless, they don’t have the skills and we lose time whilst they learn. Or we could fire them and hire another lot?



Couldn't agree more. The longer I'm in this business the more weary I grow of one-trick technologists. Yes, I think it's important to spend a lot of time with a few select tools so you don't fall into the "jack of all trades master of none" camp, but frankly better that than complete inflexibility or unwillingness to try new things.

Friday, January 8, 2010

Boxee - Boxee Box by D-Link





This looks REALLY intriguing. I read someone's take on it in which they said it has the potential to compete with Apple TV, which made me think either that person doesn't know what they're talking about, or they've never used Apple TV.

I loved my Apple TV for a while, but with the latest software update that was the last straw. I've never seen a product get increasingly worse with each update like Apple TV did, and it's more or less unusable now.

The other difference of course is that Apple TV doesn't let you watch much of anything for free. The whole point of the Boxee Box is to let you watch free Internet content on your TV without having to futz around with a computer and a browser to do so.

This is also the promise of PlayOn (http://www.playon.tv), which once my Moxi arrives I'll be experimenting with.

This is the wave of the future of TV, and paying per-episode for everything like you have to with iTunes and Apple TV is going to go the way of the dinosaur. Cable's probably next to fall.

Big Lebowski rewritten as a work of Shakespeare - Boing Boing


"The knave abideth." Sweet baby Jesus, the attention to detail in this sucker is just mindblowing! What a thing of beauty. Here's the carpet-staining scene:
shakespearepicture.jpg WOO: Rise, and speak wisely, man--but hark; I see thy rug, as woven i'the Orient, A treasure from abroad. I like it not. I'll stain it thus; ever thus to deadbeats.

[He stains the rug]


THE KNAVE: Sir, prithee nay!


BLANCHE: Now thou seest what happens, Lebowski, when the agreements of honourable business stand compromised. If thou wouldst treat money as water, flowing as the gentle rain from heaven, why, then thou knowest water begets water; it will be a watery grave your rug, drowned in the weeping brook. Pray remember, Lebowski.


THE KNAVE: Thou err'st; no man calls me Lebowski. Yet thou art man; neither spirit damned nor wandering shadow, thou art solid flesh, man of woman born. Hear rightly, man!--for thou hast got the wrong man. I am the Knave, man; Knave in nature as in name.


BLANCHE: Thy name is Lebowski.



Two Gentlemen of Lebowski, by Adam Bertocci (thanks, chris arkenberg, PLEASE PLEASE let this end up as a live stage performance for yea, verily I should like to see it)


I cannot get over how brilliant this is. The site's down at the moment but keep checking back--if you love "The Big Lebowski" like I do, you won't regret it. (If you get to the site, grab the PDF version while you can--or should I say "whilst thou can?"--so you can read offline at your leisure.)


Thanks to phenotypical for sharing this with me.


Replace Amazon S3 with MongoDB GridFS and Grails


My recent foray into MongoDB got me thinking about using it to serve files. You can do just that with MongoDB's GridFS specification. When a file is stored in GridFS, it is represented by a metadata object and one or many chunks which store a subset of the data. Chunking the files helps with searching but could help replication and sharding presumably. Files in a GridFS store are just like any object in the database. You filter by any of the metadata properties and get chunks on demand or out of order.



Very slick use of MongoDB with Grails.

Thursday, January 7, 2010

Speaking at cf.Objective() 2010

I'm proud to announce I'll be doing several sessions at cf.Objective() 2010! I was on the content advisory board this year and the schedule is looking absolutely amazing.

Here's where you can catch me at cf.Objective() 2010:



  • Polyglot Goodness: CFML on Grails (this will be a full unveiling of the CFML Plugin for Grails I've been working on)

  • Living in the Cloud: CFML Applications on Google App Engine (co-presenting with Peter Farrell)

  • Simplicity, Integrity, and Velocity: What's New in Mach-II (co-presenting with Peter Farrell and Kurt Wiersma)

  • The Duct Tape Programmer vs. the Architecture Astronaut (a rather non-traditional presentation with Simon Free, Peter Bell, Dan Wilson, and potentially some other folks)


I'll have session details before long but I'm really excited about all these topics, not to mention what else is on the schedule this year. Register now--the early bird ends on January 29!

Wednesday, January 6, 2010

Serval Professional - The world's most powerful Ubuntu laptop - system76, Inc.



Media_httpsystem76com_lesso




I have the previous version of the Serval and have never been so happy with a laptop. If you're looking to free yourself of the Microsoft or Apple tax when you buy a new machine, I highly recommend this one or any of system76's offerings.

Netgear MoCA Adapters and Verizon FiOS

In my ongoing revamp of my A/V and networking setup in my house I recently added some Netgear MCAB1001 MoCA Coax to Ethernet adapters into the mix. This is a great way to get wired networking into rooms where you have a coax connection but no ethernet, and is preferable to Wi-Fi for high-bandwidth operations like streaming video because MoCA is much faster. They claim up to 270 mbps and while I haven't done any specific speed tests myself, I can attest to the fact that it's blazing fast based on using a computer hooked into the MoCA adapter.

I did have an interesting thing happen with my setup that I figured I'd share in case anyone else runs into this. If you're on Verizon FiOS and have both internet and TV, chances are you already have MoCA. Typically if you have both internet and TV they give you an Actiontec router that has both ethernet ports and a coax port on the back of it. You plug the coax from the wall into the coax port on the router, and this allows the FiOS TV set-top boxes to get IP addresses, their channel guides, and also handles video on demand.

The Netgear MCAB 1001 has two coax ports on it, one in and one out. I assumed for this to work I'd have to plug one of the MCAB1001s into the Verizon router, so I took the coax from the wall and plugged it into the "in" on the Netgear, then took another coax cable and went from the "out" on the Netgear to the coax port on the Verizon Actiontec router.

This actually worked for a few days, but then suddenly stopped working. This was probably a coincidence but it stopped working after I threw a third MCAB1001 onto the network. The third one worked fine for a bit and then crapped out (to use a technical term). I assumed there was some problem with the configuration on the Netgear devices but after talking with Netgear support, they said I'd have to call Verizon to get the problem resolved since there were no IP addresses being handed out on the coax side of the network.

I was dreading calling Verizon because the Netgear isn't their device, and I already have a bit of a funky network setup since I don't use the Actiontec router as my main router anymore. I have to give massive kudos to Verizon support. I told them what was going on, almost apologetically since I figured they'd say "not our device, can't help you" (and rightfully so), but the support person I got went above and beyond to help me diagnose why IP addresses weren't getting distributed over the coax.

I hadn't ever dug around on my set-top box before but if you go to "Help" and then "Self-Diagnostics," it will tell you whether or not the set-top box is getting an IP address (along with a lot of other useful info). In my case it wasn't, which likely meant that the MCAB1001 I had plugged into the Actiontec router was causing issues. I went back to having the coax from the wall plugged directly into the Actiontec router and the set-top box successfully got an IP.

So at this point I had no MCAB1001 hooked into the Actiontec router at all. But to my surprise when I went to the other two rooms where I had MCAB1001s hooked up, the devices plugged into them were working. After I thought about it a bit I'm not sure why I was surprised, and I'm not sure why I thought I needed to have a MCAB1001 plugged into the Actiontec router in the first place. The Actiontec router is already using MoCA to get the set-top boxes on the network, so the MCAB1001s plugged into the coax jacks in other rooms will work the same way.

In short, if you want to use MoCA in other rooms in your house and already have an Actiontec router with coax going into it, just grab these Netgear devices and plug them in and you'll be good to go.

After two days of screwing around with this stuff it's all working fantastically well, with the only unresolved issue being why it ever worked with the MCAB1001 plugged into the Actiontec in the first place. One of life's great unsolved mysteries I suppose.

Thanks again to Verizon FiOS support for being so gracious in helping me figure this out. I had Comcast before switching to FiOS, and from experience I can say with some certainty that Comcast would have said "not our problem."

Tuesday, January 5, 2010

Graduate School in the Humanities: Just Don't Go - Advice - The Chronicle of Higher Education


The follow-up letters I receive from those prospective Ph.D.'s are often quite angry and incoherent; they've been praised their whole lives, and no one has ever told them that they may not become what they want to be, that higher education is a business that does not necessarily have their best interests at heart. Sometimes they accuse me of being threatened by their obvious talent. I assume they go on to find someone who will tell them what they want to hear: "Yes, my child, you are the one we've been waiting for all our lives." It can be painful, but it is better that undergraduates considering graduate school in the humanities should know the truth now, instead of when they are 30 and unemployed, or worse, working as adjuncts at less than the minimum wage under the misguided belief that more teaching experience and more glowing recommendations will somehow open the door to a real position.


This, in one succinct paragraph, is why I bailed on my PhD in music. I applaud people who stick it out because clearly they love it enough to keep going despite the reality of it all, but that simply wasn't me.


If this article does nothing but make those pursuing graduate degrees in the humanities think very hard about what they're doing and open their eyes to the reality of the path they've chosen, it's done its readers a great service.


Friday, January 1, 2010

New Query Functions Released in Open BlueDragon











New Query Functions released



Published: 2:01 PM GMT, Friday, 1 January 2010

We've justed finished the a whole new set of functions to help with the manipulation of Query objects and their respective datasources.



The following table highlights all the current functions within the Query category available in the OpenBD (nightly build) release:

































































DatasourceCreateAdds a new datasource to the system for use with any database functions. This does not persist over server restarts
DatasourceDeleteRemoves the given datasource. Note, it will not remove any datasource that was registered with the underlying bluedragon.xml file
DatasourceIsValidChecks to see if a given datasource has been previously registered using DataSourceCreate()
QueryAddColumnAdds a new column of data to the exist query object, returning the column number
QueryAddRowAdds the specified the number of rows to the end of the query
QueryColumnArrayReturns all the data in a query for a given column
QueryColumnListReturns all the data in a query for a given row but as a structure
QueryDeleteColumnDeletes the column from the query, returning the deleted column data as an array
QueryDeleteRowDeletes the row within a query object. Modifies the original query object
QueryIsEmptyDetermines if the query has any rows
QueryNewCreates a new query object with the columns past in of the optional types
QueryOfQueryRunExecutes a Query-of-Query against a previous SQL result sets. Function version of CFQUERY
QueryRowStructReturns all the data in a query for a given row but as a structure
QueryRunExecutes the given SQL query against the given datasource, optionally passing in paramters. Function version of CFQUERY
QuerySetCellSets the given column within a query with the value at the given row, or the last row if not specified
QuerySortSorts the query based on the column specified and the order criteria given. Modifies the original query object
QuotedValueListReturns a quoted list of all the values, for a given column within the query, delimited by the value given
ToCsvTransforms the query object into a Comma Separated Value (CSV) block
ToHtmlTransforms the query object into an HTML TABLE block
ValueListReturns a list of all the values, for a given column within the query, delimited by the value given


These functions will greatly increase the speed and efficiency to which you can work with Query objects.



Many of the functions where available using other means. For example, QueryDeleteColumn could have been achieved by performing a query-of-queries leaving out the column you wanted to remove. This however had a huge overhead, as well as duplicating the data.



You can read more about the DataSource functions over at Alan Williamson's blog.

Thanks to Peter J Farrell for many of his suggestions.






Comments (0)




Add Comment
















Great new set of query functions released in the latest nightly of Open BlueDragon! Throw(), ThrowObject(), and GetException() have also been added. Great New Year's present!