Just A Programmer We’re Just Programmers…

4Sep/110

Project Euler in F# – Problems 4 – 6

Posted by Stanley

Problem 4

Find the largest palindrome that results from the multiplication of two numbers under 1000

I feel like I have a strange obsession with the Seq.unfold function. That function does most of the heavy lifting here.

Although the wise Euler pointed out to me that I can avoid duplicate multiplication factors, and keep track of the largest palindrome so far to avoid unnecessary `isPalindrome` checks.

let problem4 () =
    let isPalindrome (value: string) =
        match value.Length with
        | x when x % 2 = 1 -> (x-1)/2, (x-1)/2 + 1
        | x -> (x/2), (x/2)
        |> fun (pos1, pos2) ->
                    value.Substring(0, pos1), value.Substring(pos2)
        |> (fun (firstHalf, secondHalf) ->

            Array.rev (secondHalf.ToCharArray())
            |> (fun reversedcharArray -> new string(reversedcharArray))
            |> (fun reversedSecondHalf ->
                    firstHalf.Equals(reversedSecondHalf)))

    let productSeq (maximumInt:int) =
        Seq.unfold (fun state ->
            let mult1, mult2 = state
            let result = mult1 * mult2

            match state with
            | 100, _ -> None
            | _, 100 -> Some((result), ( (mult1 - 1) , (mult1 - 1)))
            | _ -> Some((result), ( mult1, (mult2 - 1)))
        ) (maximumInt, maximumInt)

    let largestPalindromeSoFar = ref None

    productSeq 999
    |> Seq.filter(fun (result) ->

        match !largestPalindromeSoFar with
        | Some(largestResult) when largestResult > result -> false
        | _ -> match isPalindrome (result.ToString()) with
                  | true ->
                        largestPalindromeSoFar := Some(result)
                        true
                  | _ -> false)
    |> Seq.max

Problem 5

What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

I was so happy with my brute force solution, it looks so pretty, unfortunately it takes 3 1/2 minutes on my machine.

let problem5 () =
    let evenlyDivisibleByAllUpTo limit number =
        {limit .. -1 .. 1}
        |> Seq.forall(fun testNumber -> number % testNumber = 0)

    Seq.initInfinite(fun i -> (i + 1) * 20)
    |> Seq.find(fun testIndex ->evenlyDivisibleByAllUpTo 20 testIndex)

Project Euler’s math explains the problem a bit differently. I cant explain the formula in ten words or less, but after understanding it and applying a bit of functional style, results in this, which runs in under 1ms.

let problem5_correct () =

    let primesWithLimit limit =
        let testPrime (possiblePrime:float) =
            let sqrRootOfPrime = sqrt(possiblePrime)

            {2.0 .. sqrRootOfPrime}
            |> Seq.forall(fun divisor ->
                match divisor with
                | 1.0 -> true
                | x when divisor = possiblePrime -> true
                | _ -> possiblePrime % divisor > 0.0)

        {2.0 .. limit}
        |> Seq.filter(fun index -> testPrime index)

    let computeLimit = sqrt(20.0)

    primesWithLimit 20.0
    |> Seq.fold(fun state prime ->

        let exponent =
            match prime < computeLimit with
            | true -> floor( (log(20.0) / log(prime)) )
            | _ -> 1.0

        state * (float(prime) ** exponent)) 1.0
    |> int64

Problem 6

Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.

The brute force of this is rather innocent looking, and runs in < 1ms.

let problem6 () =

    let sumOfSquares maximum =
        {1L .. maximum}
        |> Seq.map(fun number -> number * number)
        |> Seq.sum

    let squareOfSums maximum =
        {1L .. maximum}
        |> Seq.sum
        |> fun result -> result * result

    (squareOfSums 100L) - (sumOfSquares 100L)

Following the algorithm from Euler, there isn’t much to it at all.

let problem6_correct () =

    let limit = 100L
    let sum = limit * (limit + 1L) / 2L
    let sum_sq = ((2L * limit) + 1L) * (limit + 1L) * limit / 6L
    int64(pown sum 2) - sum_sq
1Sep/115

Project Euler in F# – Problems 1 – 3

Posted by Stanley

Problem 1

Find the sum of all the multiples of 3 or 5 below 1000.

Brute force is the first thing that comes to mind

let problem1 () =
    {1 .. 999}
    |> Seq.filter (fun x -> (x % 3 = 0) || (x % 5 = 0))
    |> Seq.sum

But the wise Euler shows Math to be a better tactic, as his answer is unquestionably faster.

let problem1_correct () =
    let target = 999

    let sumDivisibleBy value =
        let p = target / value
        value * (p * (p + 1)) / 2

    (sumDivisibleBy 3) + (sumDivisibleBy 5) - (sumDivisibleBy 15)

Problem 2

Sum of all even Fibonacci numbers under 4 million

No real curveball here, unfold with a limit was the first Fibonacci method that came to mind

let problem2 () =
    let fibonacciSeq withLimit =
        Seq.unfold (fun previousState ->
            let nMinusTwo, nMinusOne = previousState
            let nextValue = nMinusTwo + nMinusOne
            let nextState = (nMinusOne, nextValue)

            match nextValue < withLimit with
            | true -> Some(nextValue, nextState)
            | false -> None
        ) (0, 1)

    fibonacciSeq 4000000
    |> Seq.filter(fun x -> x % 2 = 0)
    |> Seq.sum

Problem 3

What is the largest prime factor of the number 600851475143?

This one might take a few tries to get correct. I actually went and completed a few other Euler problems before coming back to this one.

The sample number, 13195, is the red herring here because it is so easy to get the answer if you aren’t thinking.

let problem3 () =
    let testPrime (possiblePrime:int64) =
        let sqrRootOfPrime = int64(System.Math.Sqrt(float(possiblePrime)))

        {1L .. sqrRootOfPrime}
        |> Seq.forall(fun divisor ->
            match divisor with
            | 1L -> true
            | x when divisor = possiblePrime -> true
            | _ -> possiblePrime % divisor > 0L)

    let factorSeq ofNumber =
        {2L .. (ofNumber/2L)}
        |> Seq.filter(fun testNumber -> ofNumber % testNumber = 0L)
        |> Seq.map(fun factor1 -> (factor1, (ofNumber / factor1)))
        |> Seq.takeWhile(fun (factor1, factor2) -> factor1 <= factor2)
        |> Seq.fold (fun acc (factor1, factor2) -> factor1 :: factor2 :: acc) []
        |> Seq.sort
        |> Seq.toList
        |> List.rev

    factorSeq 600851475143L
    |> Seq.find (fun factor -> testPrime factor)

That was unofficially my fourth attempt.

1Sep/112

Project Euler in F#

Posted by Stanley

While job hunting this time around, a recruiter pointed me to a website called Project Euler, as a great place to practice.

Project Euler is a series of challenging mathematical/computer programming problems that will require more than just mathematical insights to solve. Although mathematics will help you arrive at elegant and efficient methods, the use of a computer and programming skills will be required to solve most problems.

The problems always seem overly complicated, and somehow ask you to find the sum of this operation or said sequence. Most of the time, you are even provided with a sample input and output. An input I’m sure which is carefully chosen to tempt you to write a brute force algorithm.

I immediately went to do them in F#, because I find it so fun. 25 problems later… Why stop there…
After talking to Justin about it, I decided to blog my progress.

So this is a test to see how far I can get.
This might take a while…

Current Level:

28Aug/110

Knowledge Quest: Reverse engineering unmanaged DLLs

Posted by Justin

As a programmer person, I am always learning. I learn different thing in different ways, at different rates, and for different purposes. Usually, I write these blog posts about things I have learned recently. This post is about what I am currently learning.

First, a little background. Around 2006 I was programming Windows CE devices, and syncing Pocket Access databases on them with a Microsoft Access database on a desktop via ActiveSync. Since I had no need for the Microsoft Access application, but I did need to be able to write SQL queries against the Access Database, I wrote PlaneDisaster.NET.

Recently, I realized that PlaneDisaster.NET did not work on 64 bit machines. The simple fix was to compile it as a 32 bit executable. However, I wanted to make it work as a 64 bit executable. This became doubly important when I realized that I could not use OPENROWSET() on a 64 bit instance of SQL server to connect to an Access database for the same reason that PlaneDisaster.NET would not work as a 64 bit process. Of course, doubly important was still not that important in the grand scheme of things.

Eventually, I did dust off PlaneDisaster.NET and got it to work as a 64 bit executable. Running PlaneDisaster.NET as a 64 bit process requires the 64 bit version of Microsoft Office 2010 or the Microsoft Access Database Engine 2010 Redistributable to be installed. However, even after doing this, I was unable to get two features of PlaneDisaster.NET to work., compacting and repairing Access databases.

PlaneDisaster.NET makes three calls to the unmanaged function SQLConfigDataSource(). These three calls pass the commands CREATE_DB, COMPACT_DB, and REPAIR_DB respectively to the JetSQL Engine. The first one works fine with  the 64 bit driver. However,  I cannot get the second two to work. I cannot find any documentation on these calls except one MSDN document last updated in 2001 which of course was written for the 32 bit driver.

So the question is, how do I plan on figuring out how to do this? My current plan involves using Nirsoft’s DLL Export Viewer to get the addresses of the dll entry points of the unmanaged calls I am making. I will then use these addresses to step through assembly in the Visual Studio Debugger. I have only toyed with assembly. I don’t know if I will succeed in this task. However, I have already learned a lot, and I will continue to learn more. I might end up solving this problem via an alternative solution. I might simply learn enough to better articulate a question on StackOverflow that gets an answer. Or,  I might find that I am able to successfully step through the assembly and figure out this problem that way.

I will keep you all updated.

25Aug/110

Creating an Access Database In Powershell without Access installed

Posted by Justin

Recently I stumbled across a Hey, Scripting Guy! blog post titled “How Can I Use Windows PowerShell to Create an Office Access Database?” that demonstrated how to create a Microsoft Access database in powershell. The only problem with this script was it required Microsoft Access to be installed on the machine that it ran on. I knew this dependency on Access was unnecessary, because a few years ago I wrote an open source project for manipulating Microsoft Access and SQLite databases called PlaneDisaster.NET. That program did not require Microsoft Access to be installed and it allowed you to create, compact and repair databases. (I’ve discussed PlaneDisaster.NET previously on this blog.)

So, as a matter of personal and professional pride I determined that I must write a PowerShell script that could create an Access Database without requiring Microsoft Access to be installed. After all, If you can do something in C#, you can do it in PowerShell. I did have one concern. I was making unmanaged Win32 API calls via PInvoke. However, I quickly learned that’s not a problem at all. My particular PInvoke calls involve enums, but you can create enums in PowerShell. However, I ended up replacing the enums with ints in the PInvoke declarations and no one complained since PowerShell is good at figuring that sort of thing out. The code I ended up with is:

$signature = @'
[DllImport("ODBCCP32.DLL",CharSet=CharSet.Unicode, SetLastError=true)]
public static extern int SQLConfigDataSource
    (int hwndParent, int fRequest, string lpszDriver, string lpszAttributes);

[DllImport("odbccp32", CharSet=CharSet.Auto)]
public static extern int SQLInstallerError(int iError, ref int pfErrorCode, StringBuilder lpszErrorMsg, int cbErrorMsgMax, ref int pcbErrorMsg);
'@;

Add-Type -MemberDefinition $signature -Name Win32Utils -Namespace PInvoke -Using PInvoke,System.Text;

This created two static functions I could call, [PInvoke.WIn32Utils]::SQLConfigDataSource() and [PInvoke.WIn32Utils]::SQLInstallerError().

However, a new problem emerged. I could not get the script to run in a 64 bit PowerShell process. A quick google search informed me that the only way to get a 64 bit Access driver is through the Microsoft Access Database Engine 2010 Redistributable. However, even after installing the 64 bit version of that executable, my script did not work unless I ran it through a 32 bit instance of PowerShell.

After a lot of searching and frustration I eventually had an epiphany. The provider name I was using to create the database was Microsoft Access Driver (*.mdb). This provider name refered to ODBCJT32.DLL, which is only available as a 32 bit version. However, the driver that ships with the Access 2010 redistributable is called ACEODBC.DLL. This dll has a provider name of Microsoft Access Driver (*.mdb, *.accdb).  The code for this is simple:

[string] $driver = 'Microsoft Access Driver (*.mdb)';
if ([IntPtr]::Size -eq 8) {
    $driver = 'Microsoft Access Driver (*.mdb, *.accdb)';
}

Yes I’m using the size of a pointer to determine if I’m running in 32 or 64 bits.

The full script is below:

That version is hosted on poshcode.org to be more searchable. However, the authoritative one will remain as a github gist.

19Aug/110

The cost of fixing a computer, and Open Source Software

Posted by Justin

Note: I started writing this a while ago, but just finished it. This is made obvious by the time stamps of the tweets I reference.

Twitter is a great tool, but sometimes you need more than a 140 characters for a reply. This is one of those cases.

It all started with a retweet by Karen Lopez, a.k.a. @datachick:

@jlopez255: Starting today -”Name your own price computer repair”, U name the price for my labor and I will fix your computer. Parts extra.

Which lead to me putting forth the following propositions to Karen and Jennifer:

  1. It’s a problem that is is cheaper to buy a new computer than repair it for low end computers under 3 years old.
  2. We need to make repairing computers cheaper, because many individuals cannot afford what professionals rightfully charge for their skill level.
  3. OSS is better suited than closed course for bringing down the cost of computer repair.
  4. You can petition the Lord with prayer.
On point one I was preaching to the choir. On point number two I received no direct response. However, for number 3 Karen responded:
@zippy1981@jlopez255 I have not had great ease of use with OSS. For every great 1, there are 10 that require lots of Dev / tech skills.
I don’t refute this statement at face value, However, I do have the following commentary to offer backing up my third proposition.
First of all, lets limit the scope to the average personal machine owned by joe sixpack. Microsoft Office, or Open Office (or Libre Office) are power tools for these people. Other than an Office Suite, we are really talking about the web browser, and maybe the email client. For these users, a default Ubuntu install is more than enough. Most of their stuff is done on the web. Open/Libre Office are a little lacking in UX and features, but google docs makes up for the UX. Also, most of these users don’t want or need the missing features. In terms of web browsers and a window manager, the web browsers are exactly the same (yes I trained both my parents to use firefox), and the Ubuntu GUI is on par Windows 7 in terms of polish, with some interesting innovations such as how it handles full screen windows. Also, for netbooks, Ubuntu has a special install disc that tweaks the UI for the small screen.
Secondly, with Ubuntu, Linux is truly for end users. Rarely does something not work. When it fails to work, you might have to bust out the command line, but the procedures are no more complicated than what one would have to do on windows. Quite frankly, if you want a *nix OS that requires you to do a lot manually, try a BSD or Solaris.
Third, my point was OSS is better suited for reimaging hard drives cheaply than windows. Because OSS is free as in beer for all practical purposes, there are no licensing restrictions to enforce. Therefore, there are no restrictions on creative ways of deploying Linux automatically. Windows Deployment Services (WDS) and its predecessor Remote Installation Services (RIS) are expensive, and designed for enterprise deployment. Microsoft could develop a version of these aimed at mom and pop geeksquad equivalents. If such a program allowed you to entered license keys for windows, office, etc and it install fully patched versions of the licensed software, plus whatever third party stuff they wanted to add (and their was a gallery where you could pick third party free and paid software to install), that might compete with what can be achieved when your software is free as in freedom and beer. However, I honestly don’t see Microsoft doing this until someone does this with Linux first.
So my point was that OSS has better potential for automating PC repair compared to Windows. You can simplify the process with OSS which will allow less skilled people to perform PC repaired. These less skilled people will command lower fees.
14Aug/110

Yak Shaving Digest 2011-08-13

Posted by Justin

This blog post is inspired by Brendan W McAdams (blog | twitter) for introducing me to the term yak shaving, Aaron Bertrand (blog | twitter) for his Connect Digests and Jennifer Lopez (not that one) (website | twitter) for expressing  her desire to see the intersect of who she follows on twitter and who follows her, which thereby made me want to do the same thing.

I was working on a C# console app the past week or so that would find the intersect of my following and followed by list on twitter. This Saturday was dedicated to getting it suitable for github, which it now is. However, I encountered several issues along the way. Because I had some blocking issues, I allowed myself to be distracted  by every minor issue  I encountered with the libraries and tools I was using for the task, for a brief period of time. The purpose of this was to report the issues, and if possible resolve them. This lead to bug reports, feature requests, and two patches. I listed them all here to add some context to all of them.

  • OAuth issues: This actually occurred earlier in the week. Twitter uses OAuth v1, which I discovered isn’t really suited for desktop apps because you have to share the secret that associates a request with your app with the world. That’s the equivalent of being required to share a pgp private key with the world. My workaround is to simple make users of my app generate their own app key (annoying, but something you’d probably be willing to do to get CLI access to twitter). If the app becomes popular I will request xAuth access for my application.
  • Sensitive info in config files and version control. This is related to the first issue. This app was not even stored in a local git repo despite me being a SCM nazi because I needed to figure out a strategy that would allow me to push an empty app.config to github. I store my consumer key/secret in the app.config, which I point out above I don’t want to share with anyone. I solved this problem by not checking the config file into version control and having a sanitized one with a different name in version control. Also, I used configSource so all my OAuth things would be in a separate config file from the main one.
  • Being anal retentive about KBCsv overloads. I am a huge fan of Kent Boogaart‘s CSV library. In my console app, I wanted to output the results as a CSV, so I could sort the data with excel.  However, along the way I got the crazy idea  to change some constructor parameters from string[] toIEnumerable<string>. I discovered this could lead to ambiguous overloads . However, I did submit a fully working patch for IList<string> and WIP for the IEnumerable<string> with some commentary and asking if it made sense to complete the work. See patch 101185 and 101186 in the KBCsv patchlist for the actual code. I’ll call this a partial victory.
  • Filing a feature request with HelperTrinity. HelperTrinity is Ken Boogaart’s general helper library, used by KBCsv. While hacking on the KBCsv source I thought, “Hey! This could use some more helper and extension methods.” So I submitted a feature request.
  • Finding  a bug in ReSharper. Digging through the KBCsv source code lead me to find an edge case that could lead to resharper reporting a false error. So I opened RSRP-274868.
  • Filed two codeplex feature requests. I went total meta and made two suggestions for codeplex itself. Both are the sort of simple things that I expect will be received by the codeples staff with either a “great idea” or “no thats so terrible for this reason”
  • MongoDB feature requests. I constantly find the BSON implementation in the MongDB C# driver useful outside of mongodb. It was useful here, but the time it saved me was eaten up filing two feature requests. I hope to implement patches for both of them.
  • Finally, one of my twitter calls broke. Twitterizer is the library I am using for twitter, and in the middle of debugging a call that always worked stopped working. Looking elsewhere on the forums shows this is not a problem unique to me. This is the event that convinced me that my time would be better spent shaving the yak. In the end, this is still an open issue, but reverting to an older version of the library in a different branch, and excessive use of git cherry-pick made it work.
  • Epilogue: The app works, but LibreOffice does not correctly import all rows in the spreadsheet. Since its all the import columns occur before the problems occur, and this can be cleaned in a text editor, I will investigate and file the bugs appropiatly with KBCsv and LibreOffice appropriately. Also, I need to get access to a machine with Excel installed. I expect Excel to be better at parsing CSV.  It seems that I was specifying space as a delimiter in the CVS import dialog. Once I unchecked that the CSV imported properly.

So in conclusion, my app works mostly, and between my bug reports and patches, I hope that the libraries and ReSharper will be improved. Also, by writing this blog post, I hope that having the big picture will be useful to myself as I polish of this twitter utility, and implement fixes for some of the bugs.

25Jun/112

Moving your spring-roo hibernate project from Hypersonic to Postgresql

Posted by Justin

I’ve always been an ORM hater. However, recently the decision to use ORM on a project I am working on was made for me. So I borrowed a pair of my pro-ORM’s colleague’s moccasins so I could walk a few miles in them.  To throw me further out of my comfort zone, this project is being done in java, a language I am quite rusty in.

The first thing I learned about ORMs is that at least in java, you don’t pick your database right away. You start off using an in-memory database like Hypersonic until your data model is fleshed out a bit. Our project is not quite there yet, but we wanted to get familiar with the procedure for doing that. I made an attempt to use SQL Server Denali CTP1 as our database. However, that was proving difficult and another colleague suggested I use a database that might be more “java friendly.” I decided to go with my first true love Postgres.

Our ORM was hibernate. We were using the SpringSource Tool Suite or STS. This includes the development tool spring roo. Amongst many other things, roo manages your maven dependencies, and configures your hibernate persistance layer. These are the particular tasks I will concentrate on for this howto.

Installing postgres

How to do this on your particular operating system is beyond the scope of this document. I went with postgres 9.1 beta 1 just because. The lastest version of postgres 8 should be fine as well. In the examples below I am assuming your database server is running on localhost, and the user name and password you use to connect to it are both postgres. Never do this on anything besides your local laptop, and don’t even do that on your laptop if your postgres port (5432 TCP) is opened to the world.

Installing the driver

According to a comment on this stackoverflow answer, You have to use the jdbc3 postgres driver and not the jdbc4 version for hibernate to be able to generate the DDL to make the tables. My experiments have confirmed this. To install it, startup the roo shell. The roo shell can either be started from your operating system shell via roo.sh/roo.bat, or from inside the SpringSource IDE, which is a very polished eclipse distro. If you are starting up the roo shell from a terminal or command prompt, first cd to the folder where your project is located. The command to install the postgres jdbc driver is as follows:

roo> dependency add --groupId postgresql --artifactId postgresql --version 9.0-801.jdbc3
Updated ROOT\pom.xml [added dependency postgresql:postgresql:9.0-801.jdbc3]
roo>

This will take care of fetching the dependency and editing the pom.xml for you. If you want to attempt with a different version of the postgres driver, browse the different versions on mvnrepository.

Switching the persistence layer

Persistence layer is hibernate speak for database. This makes sense, because data persists in your database, as opposed to ram, cache, etc which is all meant to be temporary. Switching persistence layers in hibernate requires editing two files, persistence.xml and database.info. Editing these two by hand would violate the don’t repeat yourself rule. Luckily we can edit both with one command in the roo shell.

roo> persistence setup --database POSTGRES --provider HIBERNATE --databaseName myproject --userName postgres --password postgres
Updated ROOT\pom.xml [added dependency postgresql:postgresql:8.4-701.jdbc3]
roo>

One thing to be aware of here. The database name needs to be lower case. If you used uppercase characters, your app will not be able to connect to it.

Your persistance.xml file will now look like this:

And your database.properties will look like this:

One manual step

I have not figured out how to get hibernate to execute CREATE DATABASE if the database does not exist. So connect to postgres, and execute the following:

CREATE DATABASE myproject;

Conclusion

Hopefully, all you will need to do is debug your project as a web applicatin and the tables in your application get built. Happy coding!

11Jun/110

More Windows command line PATH goodness pathed.exe

Posted by Justin

Readers of this blog probably think I have an obsession with editing my system path. That belief is absolutely correct. I even added a tag on this blog for the articles about path manipulation. I am a command line junkie who is constantly trying out new tools so I have to add them to my path. I’ve written about doing this from powershell here and here, as well as doing it with setx. While these methods are good, I wanted something better. I got better with pathed.exe.

pathed.exe is a program that lets you edit both your user and the system path. It only manipulates the path, not other environmental variables. The reason for this extreme specialization is that pathed is specifically designed for appending to and removing from the path. It treats the path as a semicolon delimited array, which is of course what it is. For example, I just ran it now on my machine as I was writing this article (note: live coding is less embarrassing when you do it on a blog).

If you notice, their happen to be two copies of the path to mercurial on my path. Well lets fix it right now:

Wasn’t that easy?

5Jun/112

UnSQL #4 Lessons learned from PHP

Posted by Justin

Jen McCrown has decreed this UnSQL Friday theme Speaker Lessons Learned. Well what could be more a more UnSQL blog than a PHP talk that I bombed at NYPHP!

So a little back story. One day at work I discovered a problem in PHP, so I filed a bug report. I eventually fixed the bug, and my fix was included in PHP 5.3.3 and 5.2.14. I figured, “Hey this would be a great topic for a  talk!” So I gave a talk at NYPHP about how to file and fix a bug in PHP. It bombed.

It bombed for a few reasons. So let me turn my bad talk into a hopefully good blog post, about things not to do at a user group talk.

Lesson number one is don’t give an advanced talk at a user group. The problem with advanced talks at user groups is that there is one session and one talk at a user group. Not everyone in the audience is capable of digesting a one hour talk on that particular advanced topic. This is not an insult to anyone’s intelligence, most people at a given user group could eventually be made to understand your topic, most probably lack the prerequisite knowledge. My talk would have gone much better at a multi track PHP conference, because I’d only get people  that cared about my topic.

Lesson number two is giving a talk that involves mastery of an “off topic” language or technology at a user group is a bad idea. Note that I say mastery not knowledge or awareness. PHP is written in C. You need to really grok C (read: be able to clean up your pointers) to contribute to PHP. However, most PHP programmers don’t know C. I even stated in my slides “I cannot make you a C programmer in one night.” I really should have known better. To use another example, I’d be very wary about talking about CLR procs at an SQL user group because most DBAs don’t know C#, or another CLR language. You can’t write a useful CLR proc without mastering .NET. Giving a talk on CLR procs to a .NET user group could work because most .NET programmers have a basic understanding of T-SQL. As another example, you can probably give a beginner level powershell talk to a SQL user group. Its pretty easy to get a DBA from never used powershell before to making ADO.NET calls in an hour, especially if you focus on doing it with SQLPSX.

Lesson number three is be careful about a war story inspired talk. You might come off as just ranting, or even worse, like I did. Some people, like Sean McCrown, can rant well. People clamor to hear people like Sean rant. People don’t like to hear me rant. I can’t deliver a rant in a way that makes my audience feel involved like Sean does. I realized this at the time I was preparing for my talk. I said things like “the PHP SOAP module is a pile of crap,” and “the PHP community ignores people who submit actual patches.” However, I tried to do it in a non-ranty Dale Carnigieish way.  However, all that emotion lurked below the surface during the talk. When I rant people normally see an angry little nerd getting caught up in some stupid detail that doesn’t matter. In this case I spent my talk actively avoiding going into rant mode, like your friends puppy fresh from obedience school that fidgets anxiously in front of you at a slight distance, obviously wanting in his cute little puppy heart of hearts to jump on you and give you a proper puppy greeting. Since I lacked the time to emotionally distance myself from the BS I had to go through to get this bug fixed, my audience saw an little nerd that was angry about something. They were kinda confused.  Lessons learned, if you can rant like Sean, rant away. If you rant like me, make sure you can emotionally distance yourself from the topic at hand.

Could I make this talk work if I tried again? Perhaps, but I am not that interested. I gave a non-technical talk on contributing to MongoDB at MongoDC. (This post is now NoSQL as well as UnSQL. Double Rainbow all the way!!) That was well received, but had a small audience, and one of my audience members felt 10gen wasn’t open source enough. So I guess lesson number four is no one wants to hear a talk about how to contribute to an open source project. If they want to contribute, they will.