So last week, I talked about Plates, Switches, and Keycaps which means we are ready to talk about how keyboards detect keypresses. I am hand wiring keyboard so we don’t have a fancy PCB or breadboard in which to solder the pins of our keys. We have to build this key press detection system ourselves. It turns out that we need to build something called a key matrix.

Building the Matrix

On the bottom of every key switch are two pins, as shown below, that are connected when the switch is depressed.

Example 1

To begin making our matrix, we pick a pin and make a connected row across the bottom of our top line of switches. It is important to use the same side pin on each key switch to make it possible to spot and fix mistakes. If you are wicked smart feel free to mix and match. Now we are gonna make our rows out of little diodes. (I’ll explain why in a few.) Diodes allow current to flow in a single direction, so we have to make sure to put them on “facing” the right way. Since current will be coming from the column side, we face the cathode towards the row. The cathode is indicated by a black ring on our diodes. (We are using 1N4148 diodes.) Here is an example. BTW feel free to laugh at my work I had never done any of this before.

Example 2

We repeat this for all four rows of the board.

Example 3

With the rows done, I began working on the columns. For the columns, we run a cable vertically to the second pin. However, we have to make sure that the wires are shielded from the rows. If we don’t, we will have a short in our matrix. Well, if there is a short it no longer is a proper matrix, but anyway back to the important stuff. I used an Exacto blade, and made a circular cut around a stretch of wire at the position of the row 2 switch’s pin. Then using my fingernails, I made a small gap in the insulation of the wire. I repeated this process for the row 3 switch in that same column, and followed with row 1 then row 4. The result is a wire with uninsulated sections at each pin and insulated in between. There is probably an easier way…

Example 4

So you repeat that process for every column. There are special cases for wider switches. For example, this board has a two column wide space bar. In that case you wire the space to the which ever column is closet. It is super important to remember which one! Here is an example.

Example 5

I ran my columns under my rows because their is so little space in the case.

We now have the matrix done!

How the Matrix Works

The matrix works by cycling power through the columns one at a time, and listening to the rows to see what point in the matrix is connected via a key press. So in this image from PCBHeaven.com, we power up the B column while the bottom at the intersection of column B and row 3 is pressed. This sends current to row 3, and we would be able to tell that key B3 was pushed.

Example 6

This works fine even for multiple keys at once until we have three keys pressed down at once where two of the three are in the same row and two of the three are in the same column. For example if we look at the last image, what if B3, B2, and C2 were all pressed? When column C is powered, we will see C2 as pressed; however, B2 won’t be seen. Also because B2 is pressed the B column has power. This power is connected to row 3 by B3 being pressed, but since we originally powered C, the current on row 3 is interpreted as C3! This problem is known as ghosting. There is another related problem called masking. This occurs when we can not read a change because of ghosting.

To fix these problems, we use a diode on each key. In the scenario above, the B column would not get power from B2 because the diode would prevent it from flowing in that direction. So B3 would not have power, and not be seen while the C column is powered and being read.

Check out pcbheaven for more on this with great animations.

Reading the Matrix

We are going to use a teensy microcontroller as our keyboards brain. We need to connect each row and column to it. I start by connecting some bridge wires to each of them. The teensy will need it’s USB port between columns 2 and 3. so keep that in mind when cabling. I again ran my cables under the row and column cabling.

Example 7

In that picture, there is a bundle of four cables connected to the rows. I connect those to the teensy first like:

Teensy PIN Matrix
F0 row 0
F1 row 1
F4 row 2
F5 row 3

Any pin works except for Vcc, GND, RST. Just make note of what went where. I used the upper right corner as row 0, column 0.

Example 8

Now for the columns. I started on the other side of the teensy as follows:

Teensy PIN Matrix
D5 col 0
C7 col 1
C6 col 2
D3 col 3
D2 col 4
D1 col 5
D0 col 6
B7 col 7
B3 col 8
B2 col 9
B1 col 10
B0 col 11

Example 9

In the next part we’ll talk about how to program our microcontroller, the teensy, with C. Part 3 will be all keyboard layouts and then it’s about that C, and how we build the firmware for our device.

I’ve been into keyboards for quite a while, and into mechanical keyboards for the past few years. I’ve owned many so called “awesome gaming” keyboards from Razer, Microsoft, and Corsair; however, a few years ago I got my first mechanical keyboard. I wasn’t sure what the hype was all about. The gaming keyboards I had been using where in the $100 “high end” keyboard market, and I was sure nothing could be better. Then I learned about the difference between rubber dome keyboards and those with actual mechanically activated switches. I bought a CODE keyboard with Cherry MX Green switches, and it blew me away. It honestly felt good to type, and type I did for hours on that board at home, and then at work. (Sorry it was so loud former coworkers.)

Then I got the urge to get a second board, and to try some other switches. In the end I tried every kinda of Cherry Mx, Matias, and Topre switch. I also sampled Kailh and Gateron switches. The switches are the foundation components of a keyboard. They define how hard it is to press the keys (force), what it feels like to press them down (linear, tactile, or click), and how far the switches need to be pressed down (actuation point and bottom out). The rest of the article is gonna focus on Cherry Mx switches as they are the mostly commonly used switches, and my personal favorites the Matias quiet clicks. The Kailh and Gateron are Cherry Mx clones. Topre switches are a completely different type of switch that uses electro-capacitive technology under an inverted rubber cup.

Now… Now I wanna build a keyboard from scratch

No prebuilt fancyness except a teensy microcontroller, keyswitches, wires, solder and C… plain old C.

Details of Cherry Mx and Matias Switches

The first thing to know about switches, is that there is no single best switch. Different switches are preferred for different usages and vary by each individual. You can see a good breakdown of the stats about Cherry Mx switches on wikipedia. As a synopsis of that information basically switches are divided by their feel and weight. Keyswitches have two important points in the keystroke, the actuation point and the bottom out point. The actuation point is when the keystroke is registered, and bottoming out is when it hits the bottom of the switch. On a rubber dome keyboard these are often one in the same. So the keystroke is registered when the the PCB underneath the rubber dome is touched. This hurts my hands just thinking back to those days. If you take a look at an animation of the Cherry Mx Clear switch. (my personal favorite)

Cherry Mx Clear

You can see the way the tactile bump tells the user the switch has been actuated early in the keystroke. Once you learn to feel for that bump, you can swiftly and lightly press the switches to just that point and avoid the abrupt stop of bottoming out. The tactile bump is one type of Cherry MX switch feeling, some switches also make an audible clicking sound; however, some people prefer the smoothness of a linear switch. With a linear switch there is still quite a bit of separation between the actuation point and bottoming out, and you can learn to touch type on them as well. The weight of a switch refers to how hard you have to press to reach the actuation and then bottom out point. Typically a light switch is around 45g of force to actuate with mediums around 55g and heavy switches anything higher than 60g. Bottoming out force is often either the same or slightly lower than the actuation force.

Here is a simple chart with the most common types of Cherry Mx Switches:

Switch Type Weight Type
Black Heavy Linear
Red Light Linear
Brown Light Tactile
Clear Medium Tactile
Blue Medium Click
Green Heavy Click

The Matias Quiet Click switch is roughly the same specs as a Cherry MX Clear but with a higher actuation point and a stronger bump. It also gives in completely after actuation with just a 35g bottoming out force compared to the 45g of the Clear. This makes it easier to feel the switch give and start to pull the finger back up. Due to some old hand injury, it’s this bottoming out that causes pain in my fingers after a few hours of typing on a rubber dome or laptop keyboard.

The switches snap into metal plates or mount directly onto PCBs depending on the desired feel and type of keyboard. Since we’re building from scratch I won’t have a premade fancy PCB I’m going to be doing some old fashion hand wiring. The plate I’m using is from Ortholinear Keyboards and is called an Atomic keyboard. It’s a grid like board with a small 2 unit space key. Here is an example of the plate and some switches installed on it and one waiting to go in.

Example 1

You might notice the the stems of these switch are a plus sign and kind of a translucent white colors. The plus sign is the standard for all Cherry Mx Switches, and the color tells me this is a Clear switch. (trust me on that one) On the switch to the left, it’s two units wide, so we have the keyswitch surrounded by a stabilizer. A stabilizer is used to make sure that a key presses down evenly no matter where on the key you press it. We’ve all had that weird space bar that kinda pushed down awkwardly. (I’m looking at you Microsoft Ergo 4000!) There are several different types of stabilizers; however, the ones pictures are a plate mounted Cherry Mx stabilizer.

Disassembled Cherry Stabilizer

A stabilizer is made of two plate mounted slides, two sliders and a small bar that ensures that both sides of the stabilizer move up and down together. Just like the key switches, they snap into the plate. Here is a view of those same switches from the bottom

Bottoms Up

Keycaps

Keycaps are a subject one could get lost in but from a basic stand point they are typically made from ABS or PBT plastic. PBT keycaps normally have a nicer texture, and are thicker and better made than ABS keycaps. Nonetheless, the simplicity and variety with which ABS keycaps are made make them extremely popular in the show off crowd. I want a board that feels good, but some extreme keyboard modders just wanna look good. There are entire parts of the internet devoted to just this part of keyboarding alone. (sigh so many wasted electrons). Anyway for my build I’m using some high quality simple PBT keycaps from Signature Plastics Here’s a good pic of them from below.

Keycap stabs

You can see there are stabs built inside the keycap to accept those plus sign posts on the switches, and the longer switches with the stabilizers have multiple stabs. The position of these stabs depends on the layout of your keyboard and how the switches are positioned on your plate or PCB. Since, I’m crazy nothing about this board is standard, but it is very geometric :). So here is our board after putting on the keycaps.

Keyboard Part 1

In the next part we’ll talk about how keyboards work and how we’re going to wire this beast up to our microcontroller. Part 3 will be all keyboard layouts and then it’s about that C, and how we build the firmware for our device.

I’ll leave you with some of my previous keyboards during my misspent designer phase.

HHKB Eve Set Dolch Set Dual Color

So I have a node.js application that contains the getAccountInfoFromToken function below, and I want to test it with Mocha. This function has been gutted and the account details are embedded now instead of called in to make the example clearer.

Promise = require('bluebird'),
getAccountInfoFromToken: function(token) {
    return new Promise(function(resolve, reject){
        // Get Account details
        var sample_return = {
            "accounts": [
                {
                    "account_id": 1725389
                }
            ],
        };
        var accounts = sample_return["accounts"];
        if (accounts.length > 0) {
            resolve(accounts);
        } else {
            reject('No Accounts');
        }
    });
}

So initially I took a very naive approach to the test because I wasn’t clear on how javascript compared arrays. So I had the test you see below.

"use strict";

describe("token_vending_machine", function () {
    var tvm = require("../src/server"),
        sinon = require("sinon"),
        assert = require("assert"),
        expected_token_return = [
            {"account_id": 1725389}
        ];

    describe("#getAccountInfoFromToken()", function () {
        it("should return the right details when called with a token", function () {
            tvm.getAccountInfoFromToken("test").then(function (data) {
                assert.equal(data, expected_token_return);
            })
        });
    });
});

However Mocha would report that as a pass but then I got an error from Bluebird about a possibly unhandled AssertionError… like you see in the output below.

token_vending_machine
    #getAccountInfoFromToken()
    ✓ should return the right details when called with a token
Possibly unhandled AssertionError: [{"account_id":1725389}] == [{"account_id":1725389}]
    at /Users/jmyers/dev/token_vending_machine/test/tvm.js:40:24
    at tryCatch1 (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/util.js:43:21)
    at Promise$_callHandler [as _callHandler] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:627:13)
    at Promise$_settlePromiseFromHandler [as _settlePromiseFromHandler] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:641:18)
    at Promise$_settlePromiseAt [as _settlePromiseAt] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:804:14)
    at Promise$_settlePromises [as _settlePromises] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:938:14)
    at Async$_consumeFunctionBuffer [as _consumeFunctionBuffer] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/async.js:75:12)
    at Async$consumeFunctionBuffer (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/async.js:38:14)
    at process._tickDomainCallback (node.js:463:13)


1 passing (8ms)

That possible assertion error is a real thing because I thought my test was passing when it wasn’t because Mocha wasn’t getting the information it needed. Next I tried to catch the error and throw it. So I edited the test like so…

    describe("#getAccountInfoFromToken()", function () {
        it("should return the right details when called with a token", function () {
            tvm.getAccountInfoFromToken("test").then(function (data) {
                assert.equal(data, expected_token_return);
            }).catch(function (err) {
                console.error(err);
            })
        });
    });

That lead to a timeout error, which actually made Mocha show the test as failing. It also logged what the actual error was. That output is below

token_vending_machine
    #getAccountInfoFromToken()
{ [AssertionError: [{"account_id":1725389}] == [{"account_id":1725389}]]
name: 'AssertionError',
actual: [ { account_id: 1725389 } ],
expected: [ { account_id: 1725389 } ],
operator: '==',
message: '[{"account_id":1725389}] == [{"account_id":1725389}]' }
    1) should return the right details when called with a token


0 passing (2s)
1 failing

1) token_vending_machine #getAccountInfoFromToken() should return the right details when called with a token:
    Error: timeout of 2000ms exceeded
    at null.<anonymous> (/Users/jmyers/dev/token_vending_machine/node_modules/mocha/lib/runnable.js:157:19)
    at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

Now I knew I needed to use a deepEqual to get the test to pass; however, I still didn’t wanna have to wait 2 seconds per test for my test to get marked as a failure. Enter Mocha’s done function which tells Mocha that the test is complete. It needs to be called after the assertion, and in the error handler in order to work properly. Here is the updated test.

describe("#getAccountInfoFromToken()", function () {
    it("should return the right details when called with a token", function (done) {
        tvm.getAccountInfoFromToken("test").then(function (data) {
            assert.equal(data, expected_token_return);
            done();
        }).catch(function (err) {
            done(err);
        });
    });
});

the clearer Mocha output:

token_vending_machine
    #getAccountInfoFromToken()
    1) should return the right details when called with a token


0 passing (6ms)
1 failing

1) token_vending_machine #getAccountInfoFromToken() should return the right details when called with a token:
    AssertionError: [{"account_id":1725389}] == [{"account_id":1725389}]
    at /Users/jmyers/dev/token_vending_machine/test/tvm.js:35:24
    at tryCatch1 (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/util.js:43:21)
    at Promise$_callHandler [as _callHandler] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:627:13)
    at Promise$_settlePromiseFromHandler [as _settlePromiseFromHandler] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:641:18)
    at Promise$_settlePromiseAt [as _settlePromiseAt] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:804:14)
    at Async$_consumeFunctionBuffer [as _consumeFunctionBuffer] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/async.js:75:12)
    at Async$consumeFunctionBuffer (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/async.js:38:14)
    at process._tickDomainCallback (node.js:463:13)

Now to actually make the two arrays compare properly and getting a passing test. All that we need to do is to do a deepEqual instead of an equal.

describe("#getAccountInfoFromToken()", function () {
    it("should return the right details when called with a token", function (done) {
        tvm.getAccountInfoFromToken("test").then(function (data) {
            assert.deepEqual(data, expected_token_return);
            done();
        }).catch(function (err) {
            done(err);
        });
    });
});

And our happy Mocha output:

token_vending_machine
  #getAccountInfoFromToken()
    ✓ should return the right details when called with a token


1 passing (6ms)

The Importance of Early (Organizers)

One of the most important time periods for a conference is the early bird periods. So you know you want to have an event, and the CFP is taking off. But, how on earth do you make it reality. This is where early birds and launch sponsors are a HUGE help. One of the most expensive parts of a conference is that up front section where you are need to secure vendors and make deposits. You’re not sure how big of a success your conference is going to be and you’re nervous about being on the hook for all these expenses.

Reaching out and engaging your potential attendees early is critical. It builds excitement for the event not on in them, but also in you. It’s this early excitement that you need to secure the initial funds required for a great event. In the early bird periods, you’d like to get roughly 40% of your tickets sold. The fervor will increase as the event gets closer, but deposits are a very, very real thing that is due up front. Consider offering hugely discounted tickets or other perks such as unique swag or recognition for your early bird and launch sponsors.

Don’t get discouraged, it’s a war and it will take time. You won’t sell out of tickets before the scheduled is even announced. So don’t fret it if you make your deposits, but don’t see every ticket. Keep contacting and reaching out to people.

The Importance of Early (Attendees)

If you are interested in an event, not only can being an early bird often save you money, but it ensures the viability of the event. It also keeps the organizers from going insane. It’s a HUGE undertaking to run an event, and the high they get with each ticket sale will propel the organizers to do even more than they often envisioned. Plus in community conferences, it’s people who have a shared interested in the same thing you do, and want to make a better community. This is a super simple way to push that forward.

The Importance of Early (Sponsors)

Being an early sponsor is great for your company. It makes sure you are the first name people see when they hit the website, and often those websites are hit most during the call for proposals, ticket sales launch, and the month leading up to the event. If you get in early, you’ll be there for all three of those time periods. Often times you can negotiate reduced rates or additional perks like special shout outs and mentions above your sponsored level. You also demonstrate to everyone visiting that page, that you care about the community in which they work. They will remember that the next time they need a service or are looking for a new job. Community focused customers and employees will push you to new heights. Also, many times you are a member of that same community and will want your own employees to attend. Your early sponsorship helps ensure the success of the conference.

This post is part of a series:

Proposals

Selecting proposals from the CFP process is very difficult, and you need a very diverse group of talk selection committee members. It is also one of the first parts where PR can get out of hand and negativity brews around the event. We received over 100 proposals, and we had a total of 36 slots… UGH.

PyCon has a great selection process in my opinion. It shifts through HUNDERDS of talks. You can see the details here. We adapted that slightly to fit the smaller scale of PyTennessee.

Overview

  • By Nov 3rd: Initial review took place on the website. The committee reviewed each proposal, left feedback for the author, and voted on the proposal using an “identify the champion” system. We also meet occasionally on IRC to discuss talks and coordinate feedback to presenters.
  • Nov 3rd: IRC review begins. The first round, nicknamed “kittendome”, reviewed each talk in isolation, determining if the proposal would be a “good talk” for PyTN. Some talks were rejected at this point; the rest will passed on to…
  • Nov 3rd: The second round, nicknamed “Thunderdome”. The remaining talks (typically about half of the proposals) were grouped by topic into groups of 3-5. During Thunderdome, we’ll discussed one group at a time, and select the best talk(s) from each group.
  • Nov 4th: Notify Speakers
  • Nov 15th: Publish Talk listing

Initial Review

The committee had two goals here: * Give feedback to authors and help them improve their proposals (authors could edit proposals up until the CfP closes). * Get an initial set of votes from as many committee members as possible. This will inform the later meetings.

We made sure that each talk got reviewed by at least 3 committee members (and ideally more).

Voting

The process we used to assess proposals was based on the Identify the Champion process. The idea is to to assess each talk and identify “champions” and/or “anti-champions” – people who will argue strongly for or strongly against a talk in initial review.

The document linked above uses an “A/B/C/D” scale for reviewing; we use the same idea, but use “+1/+0/-0/-1” labels (after the Apache voting system). These votes mean:

+1 – I will champion the talk at the program committee meeting. The topic sounds good and the proposal is solid. This vote means you’re willing to put your reputation on the line in favor of the proposal and its author, and that you believe PyTN would be worse off for not having the talk.

+0 – This topic is good and the proposal is solid. The speaker is capable of correcting any deficiencies, and I think a significant number of PyTN attendees would want it available. I don’t feel strongly enough about it to serve as its champion at the program committee meeting.

-0 – I am not in favor of this talk as proposed. The talk, the topic, or the proposal has problems that concern me. I’d rather see it not accepted.

-1 – This talk or its proposal has significant problems. I believe that PyTN would be worse off for having it, so I will argue strongly to reject this talk.

If you don’t know enough about a topic to judge a proposal’s coverage of it, or it’s a topic you tend to actively avoid, you should not recuse yourself from voting on that basis alone. You can still judge the structure of the proposal, the likelihood that the speaker can cover the material proposed in the time allotted, whether the topic is likely to appeal to others, etc.

“Obvious” accepted/rejected talks

After the initial review, there will be a small set of talks that are “obviously good” or “obviously bad”. We’ll set a threshold, by committee consensus, for talks that are automatically rejected or get to automatically skip ahead to Thunderdome. This is usually something like “reject all talks with 3 or more -1s and no +0s or better” or “accept all talks with at least 4 +1s and no -1s”. Let me know your thoughts

These accepted talks aren’t a free pass to PyTN - it just means that the talk goes directly to Thunderdome. A reject is final, however; it weeds out the few obviously bad proposals that nobody on the PC wants to support. After the initial review we had nine 45 minute talks, and six 30 minute talks that all had roughly equal ratings, or a program committee member who really wanted to raise a talk up the rankings.

IRC Meetings

Next, we held meetings in IRC to discuss the talks. We allowed a champion to speak for the talk being discussed, and allowed the rest of the program committee to respond. We then took another vote. This process continued until all of those talks were refined down to the list you see on the schedule, and a set of backup talks.
There we three attempts to add a 5th track to the conference to accommodate more of the talks. We wanted to accept many more talks than we did; however, we have a big enough event on our hands now for a first one. Then we wrapped up with a vote on the conference as a whole. The question was, “Did anyone feel that any one talk would detract from PyTennessee being a great conference?” After that passed, we have the list you see today

Kittendome

In the first round of meetings, we went through each proposal individually. The goal here was simple to determine if a given talk – reviewed in isolation – is potentially good enough for PyTN. That is, in the first round we reviewed talks strictly on their merits and avoid holding them up against similar talks (we do that next, in Thunderdome).

We reviewed talks, one at a time. We gave a couple minutes for the champions (identified by the website votes) to make an argument for the talk. Then, a few minutes of general debate. Finally, we voted yay/nay on each talk. Majority rules - a majority of “yay” votes will indicated that the talk was accepted – it moves onto Thunderdome. A majority of “nay” votes indicated that the talk was rejected – it’s out. The chair will break ties.

Thunderdome

After round one has ended, we’re left with a set of talks that are all “good enough” for PyTN, and so we pit similar talks head-to-head and try to select the best.

In each “round” of Thunderdome we reviewed 3-5 talks, roughly grouped by theme/content/topic/etc. Out of each group we’ll got one or more winners, possibly some damaged talks, and some talks that are out. We did this by discussing, and then the committee voted for the talks they liked. Members voted for any number of talks (including none or all of them).

The winners were the talks from the group that absolutely should be at PyTN. It advanced and was safe from future cuts. It’s on the program! The winners were talks that had a 75% supermajority.

Damaged talks were ones that had been voted down by Thunderdome but aren’t quite out of the running yet. There may not be any damaged talks in a given group, or all talks may end up damaged. Damaged talks are any talks that didn’t win, but did receive votes from at least 50% of the committee. Talks that were selected by fewer than 50% of the committee in attendance are out – they will not appear at PyTN.

We then allowed a champion to speak for each damaged talk, and allowed the rest of the program committee to respond. We then took another vote. This process continued until all of those talks were refined down to the list you see on the schedule, and a set of backup talks.

There we three attempts to add a 5th track to the conference to accommodate more of the talks. We wanted to accept many more talks than we did; however, we have a big enough event on our hands now for a first one.

Then we wrapped up with a vote on the conference as a whole. The question was, “Did anyone feel that any one talk would detract from PyTennessee being a great conference?” After that passed, we had the list that appeared at the conference.

UGH… DRAMAS

We attempted to do a fair and honest review of the talks, did we do a perfect job… No. Program Committee members were not allowed to submit talks, share talk reviews, or beseech outside opinions. During Kittendome and Thunderdome people abstained from voting for coworkers, bosses, close friends, etc. In my case, that meant I cast less than 5 votes the entire dome process for individual talks. :( I’m certain people could find flaws in our process, or point out some sort of bias.

I can be bought with Cookies, and that’s really no secret.

So what kind of drama did we have?

Well first, we were clear from the onset that we wanted to be a different conference. We picked a diverse group of talks, and didn’t limit ourselves to just python or even code. In fact, two of the highest vote getting talks were on Systematic Bias and Mental Health. Those were contentious in the organizers group, but the amount of “not python” was a shock to people. I got emails calling me stupid, saying I destroy the conference, and that I was doing Python a disservice.

Secondly, we choose to allow presenters to have multiple talks. During the domes, we didn’t pay attention to how many times a speaker names appeared in our selected talks other than to decide if we could vote or not due to some potential bias. After the committee members were done selecting talks, they noticed that a few speakers had multiple talks chosen. A discussion then occurred, and the decision was made to say these were the talks chosen, they are the talks that should be presented. Unfortunately, many of these people were friends or close to a few of the organizers. This also caused several emails accusing us of playing favorite or placating big name presenters, etc.

Finally, A few people we turned down sent nasty emails about how well known they were, or how great a presenter they are and how stupid I was for turning them down. In a few cases the submitted proposal was one line about the content and several lines about past presentations. As you can imagine the committee voted that talk down over one with a nice full proposal. I still got told I had no business running a conference, I obviously knew nothing about development, and that “my talk would have been selected at” conference X.

These three days lead to a massive cry!!! Thanks to strong support from the committee and a few members of our local community I made it through. I knew we had a great set of talks selected, and I knew that it was done as fair as possible. And a week later the drama had died down and people began to get excited about the talk selection and were tweeting about it.

And now looking back after the conference. It was totally worth all the drama. We had an overwhelmingly positive response at the event. I and the rest of the committee were ecstatic with the results.