Sunday, December 26, 2010

You are Beautiful Birmingham

Birmingham Metro must change the focus from ME to WE.  Fragmented geopolitical segmentation of the Birmingham Metropolitan (Metro) will continue to produce squabble.  History of the area guarantees this is the most likely outcome.  The basis of the separation is a lack of trust: centuries of dishonesty between races and political factions created barriers more real than municipal lines.  Birmingham Metro is composed of varying entities representing a balance of power, which is proven to fail all parties.  We should build a larger ideal; we are on the same team; we are Birmingham; you are Birmingham.

Who are you competing against?

Birmingham city is not competing against Hoover.  Mountain Brook is not competing against Vestavia.  Hoover is not competing against Birmingham city.  Consider the Southeastern Conference: teams share half of their bowl payouts with the conference.   The conference collectively bargains for TV viewing rights.  The SEC separates their competition on the field as being the product, and the cooperation off the field as their livelihood.  It is in Alabama’s best interest to have a strong Auburn (and vis-à-vis).  It is in Birmingham’s best interest to have a strong Hoover.  It is in Mountain Brook’s best interest to have a strong Birmingham.  Our competition is Nashville, Atlanta, Indy, and Austin, not each other.

In a Leadership and Creativity class lead by the late Dr. Paul Preston at Montevallo, we performed an exercise on negotiation and cooperation: in groups of two, we were told to negotiate with counterparty for the best price on oranges.  Our primary goal was for the best price, but hidden within our instructions were our needs: one needed the juice and the other needed the rind.   The counterparties could only discover potential cooperation with discussion and showing their cards.  Elements of vulnerability were required for the greatest outcome.  Of the 20 counterparty pairs, only one group found the differing needs – therefore, the best outcome is elusive, requires vulnerability, and creativity.

Education in Birmingham

In Birmingham, the “third rail” is education.  It will provide the power for change, yet will be divisive.  I consider each school system in Birmingham to be a private system.   My reasoning: school performance is directly associated with per-capita income from the surrounding tax base.   Instead of directly paying tuition, individuals purchase land within the tax base, then pay the tuition (i.e. property tax), or create a education foundation (which should be dissolved).  I know the caveats around my thought: each system has decided their emphasis and allocation of resources.  It remains:  people with children purchase land associated with school systems; the land represents a share in a school system just as a shareholder purchases shares in corporation.

Whether you agree with my Private School Theory, you have to agree it is in each municipality’s best interest to have smarter people in neighboring areas.  Certain areas of Birmingham have core competencies in education.  Certain areas have created vicious cycles.   For business, for the future, it is in each person’s best interest to have better education systems.  Mountain Brook, Hoover, and Vestavia need to exploit their core competencies in education and bring up the City system.  The City system needs to understand its misallocation of resources, and accept guidance from those better at performing the task.

Because each city in Birmingham has the right to manage resources differently, we can think of them as different economies.  Each city has differing cash flows, similar to countries.  Birmingham is a net importer: it pays for experienced human resources to come into the city.  Mountain Brooke and Vestavia are net exporters: they provide experienced human resources to other areas.   Viewing cash flows this way, the Birmingham occupational tax is a tariff on importing human resources.   Birmingham has to import because its school system is deficient.  Yet, the core competency for Birmingham city is business.

Each part of Metro Birmingham has a core competency, which if explored like juice and rind would make the whole work better.   It will take vulnerability, creativity, and breaking down the history of mistrust.  You are Birmingham.

We need to begin building our educational, business, and government infrastructure to ensure we are on par in the future.

Thursday, November 18, 2010

Reading Excel files using JRuby and Apache POI

In the code below, I am reading Microsoft Excel files using JRuby and the Apache POI library.  You will need the following, which you can get from http://apache.org/:


  • commons-logging-1.1.jar
  • dom4j-1.6.1.jar
  • geronimo-stax-api_1.0_spec-1.0.jar
  • junit-3.8.1.jar
  • log4j-1.2.13.jar
  • poi-3.6-20091214.jar
  • poi-contrib-3.6-20091214.jar
  • poi-examples-3.6-20091214.jar
  • poi-ooxml-3.6-20091214.jar
  • poi-ooxml-schemas-3.6-20091214.jar
  • poi-scratchpad-3.6-20091214.jar
  • xmlbeans-2.3.0.jar

I don't remember which ones I used, but those are the ones which were in the library when it worked.  According to the code below, you will want to put those in "lib/java_classes." However, you can put them wherever.

The code below outputs the Excel spreadsheet as an array:

Dir.new("lib/java_classes").sort.each do | file |
  require("lib/java_classes/" + file) if file =~ /\.jar$/
end

include_class Java::org.apache.poi.poifs.filesystem.POIFSFileSystem
include_class Java::org.apache.poi.poifs.filesystem.POIFSFileSystem

include_class Java::java.io.ByteArrayOutputStream
include_class Java::java.util.Date


require 'yaml'

args = YAML::load(STDIN)

input = Java::JavaIo::FileInputStream.new(args["file"])

include_class Java::org.apache.poi.ss.usermodel.WorkbookFactory
include_class Java::org.apache.poi.ss.usermodel.Workbook
include_class Java::org.apache.poi.ss.usermodel.Sheet
include_class Java::org.apache.poi.ss.usermodel.Row
include_class Java::org.apache.poi.ss.usermodel.Cell
include_class Java::org.apache.poi.ss.usermodel.FormulaEvaluator

@spreadsheet = WorkbookFactory.create(input)
@formula_evaluator = @spreadsheet.get_creation_helper.create_formula_evaluator


def parse_value(cell)
  return nil if cell.nil?

  case cell.get_cell_type
  when Cell.CELL_TYPE_NUMERIC then cell.get_numeric_cell_value
  when Cell.CELL_TYPE_STRING then cell.get_string_cell_value
  when Cell.CELL_TYPE_FORMULA then parse_formula(@formula_evaluator.evaluate(cell))
  when Cell.CELL_TYPE_BOOLEAN then cell.get_boolean_cell_value
  when Cell.CELL_TYPE_BLANK then nil
  else
    raise "Don't know what to do with cell type: #{cell.get_cell_type}"
  end
end

def parse_formula(cell_value)
  case cell_value.get_cell_type
  when Cell.CELL_TYPE_NUMERIC then cell_value.get_number_value
  when Cell.CELL_TYPE_STRING then cell_value.get_string_value
  when Cell.CELL_TYPE_BOOLEAN then cell_value.get_boolean_value
  when Cell.CELL_TYPE_BLANK then nil
  else
    raise "Don't know what to do with cell type: #{cell_value.get_cell_type}"
  end
end

spreadsheet_as_array = ([email protected]_number_of_sheets - 1).map do | sheet_num |
  sheet = @spreadsheet.sheet_at(sheet_num)
  sheet_as_array = [sheet.sheet_name, []]

  sheet.row_iterator.each do | row |
    sheet_as_array[1] << []

    row.cell_iterator.each do | cell |
      sheet_as_array[1].last << parse_value(cell)
    end
  end

  sheet_as_array
end

puts spreadsheet_as_array.inspect

There is a flaw to this code above: an Excel sheet needs to be "cleaned" prior to importing.  Excel files typically get tons of extra rows and tons of extra columns associated with the Active Cells.  People apply formatting to unused areas by selecting all, etc.  Therefore, go in and delete unused cells, and do "Save As" to get Excel to forget formatting on those cells.

To run the code above, do the following:

echo 'file: my_spreadsheet.xls' | jruby xls_to_array.rb

Statistically Improbable Cheating

I recently ran across an article on finding test cheaters with statistics(http://www.telegraph.co.uk/news/newsvideo/weirdnewsvideo/8140456/200-students-admit-cheating-after-professors-online-rant.html), and I remembered an event I had when I was a teacher.  Then, I recovered this from a message on 03/16/2005 when I was a teacher:

I had my students a test recently that contained 65 multiple choice questions. Also, I had a student tell me  my class was easy, so I considered that a challenge to whoop the students with the next test.
So students are taking the test (which I give on computers, and it grades automagically) and the grades are coming back between 40's and 65's.  Then some more classes come in and they start making between 40's and 80's.  So the final average average is about 55.  There is a good equal distribution so I can work with it.


I start figuring out how I am going to scale the test (and in public schools they frown on true Bell Curves.  They are really looking for a line with about 5% failing and 30% A's. ). So I do some computer stuff and figure that I will split the hardest questions from the easiest on a scale with 5 steps.  The hardest are worth 1.8 and the easiest are worth 2.2.  That gives me a good line, and theoretically removes any bonuses for guessing correctly.


So, I get this knocked out. Finally I decided to write a little script to see if anyone is cheating.  I examine everyone's answers, and the odds of two people having 60 of 65 of the same answers on the test is highly unlikely. Seeing how most only got 55% correct, correlations between two different test-takers should not be there.


After I run this script, I get 4 sets of students that have 60 similar answers. 3 of the 4 sets sit right next to each other.  1 of the 4 sets has one student that sits directly behind the other.  There are no other correlations.


Convenient huh?


The odds of two students out 100 that are in of five classes sitting directly next to each other randomly putting the same answers for 60 of 65 four choice multiple questions the exact same is .00064%.


I think it was just brain waves interfering.

Wednesday, November 17, 2010

Using Math with Ruby Ranges

Back in August, I wrote a little Ruby library that extends math functions to ranges (https://github.com/Winslett/RubyRanges). The sole purpose of the library was to easily work with schedules and conflicts.

For instance, given I am available from 2 to 6, yet have scheduled events at 3 to 4 and 4:30 to 5:15, I could use simple math functions like the following:

  (2010-11-17 14:00:00..2010-11-17 18:00:00) - (2010-11-17 15:00:00..2010-11-17 16:00:00) - (2010-11-17 16:30:00..2010-11-17 17:15:00)

Should equal an array of ranges of times the person is available:

  [(2010-11-17 14:00:00..2010-11-17 15:00:00),(2010-11-17 16:00:00..2010-11-17 16:30:00),(2010-11-17 17:15:00..2010-11-17 18:00:00)]

Please take the library. I look to convert it into a Gem soon, but job comes first.

Chris

Tuesday, November 16, 2010

Automating Microsoft Word with IronRuby

Below some snippets with details of a project I worked on for documentation creation workflow.   A core focus of the project was reduce the number of steps needed by a person to automate a document creation and distribution process.

At the basis of the organizational knowledge is Microsoft Word and Excel, therefore, we stuck with Microsoft Word and Excel.  Given I introduced more base technology, I would have to support more base technology.  Therefore, I tried to minimize change and maximize return-on-technology.

Each document was a mail merge file in Microsoft Word.  Each mail merged document had multiple receipts, and the routing and packaging of documents could be either physical or E-mail.  The physical distribution had a variable number of copies based on receipts, and the E-mail distribution had a single copy with a variable number of recipients.

Now for the code:

Below loads the information into IronRuby:
require 'Microsoft.Office.Interop.Word, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'

Below I abstracted the Microsoft Word interface:
class Word
  attr_accessor :word, :documents

  def self.connect
    word = Word.new
    word.word = System::Runtime::InteropServices::Marshal.get_active_object("Word.Application")
    word.documents = (1..word.word.Documents.Count).inject([]) do | documents, num |
    documents && Document.new(:document => word.word.Documents[num])
    end
    word
  end

  def self.open
    word = Word.new
    word.word = Microsoft::Office::Interop::Word::ApplicationClass.new
    word.visible
    word.documents = []
    word
  end

  def visible
    word.visible = true
  end

  def close(args = {})
    args[:force] ||= false
    word.Quit(args[:force])
  end

  def printers
  System::Drawing::Printing::PrinterSettings.InstalledPrinters.map { | p | p }
  end

  def active_printer
  word.ActivePrinter
  end

  def active_printer=(arg)
  word.ActivePrinter = arg
  end

  def disable_alerts
  word.DisplayAlerts = Microsoft::Office::Interop::Word::WdAlertLevel::wdAlertsNone
  end

  def enable_alerts
  word.DisplayAlerts = Microsoft::Office::Interop::Word::WdAlertLevel::wdAlertsAll
  end
  
end

Below is the Document object. While working, I originally started with Document controlling the Word and Document objects, but eventually realized I needed to split the two:

class Document
  attr_accessor :document

  def initialize(args = {})
   self.document = args[:document]
  end

  def name
    document.Name
  end

  def ToString
    name
  end

  def self.find(*args)
    @@word ||= Word.connect

    case
    when args[0].is_a?(Fixnum) then
      @@word.documents[args[0]] || raise(WordErrors::DocumentNotFound, args.inspect)
    when args[0].is_a?(String) then
      @@word.documents.find { | document | document.name == args[0] } || raise(WordErrors::DocumentNotFound, args.inspect)
    when args[0] == :all then
      @@word.documents
    else
      raise(WordErrors::DocumentNotFound, args.inspect)
    end
  end

  def self.open(file_path = nil)
    @@word ||= Word.open

    document = Document.new(
      :document => !file_path.nil? ?
      @@word.word.Documents.Open(System::String.new(file_path)) : @@word.word.Documents.Add
    )

    @@word.documents << document
    document
  end

  def mailmerge?
    document.MailMerge.State != 0
  end

  def close(args)
    save_changes = args[:force] ? false : true
    @@word.documents.delete(self)
    document.Close(save_changes)

    if @@word.documents.length == 0
      @@word.close(:force => true)
      @@word = nil
    end
  end

  #
  # record => Fixnum, :first, :last, :previous, :next, [Fixnums]
  #
  def goto(record)
    return true if record == :current || current_record == record

    case
    when record.is_a?(Fixnum)
      document.MailMerge.DataSource.ActiveRecord = record
    when record == :last
      document.MailMerge.DataSource.ActiveRecord = record_count
    when record == :first
      document.MailMerge.DataSource.ActiveRecord = 1
    when record == :next
      document.MailMerge.DataSource.ActiveRecord = current_record + 1
    when record == :previous
      document.MailMerge.DataSource.ActiveRecord = current_record - 1
    else
      raise(WordErrors::RecordNotFound, "Cannot use '#{record}' to find a record")
    end
  rescue
    raise WordErrors::NotMailMerge unless mailmerge?
  end

  #
  # Expects the following variables to be passed:
  #
  # action => [:print, :save]
  #
  # args =>
  #
  #   :records           => [:all, :current, :next, :previous, :first, :last]
  #   :path              => path to the directory which will save the files
  #   :directory_formula => The formula for the directory based on the
  #                         Investors datasource values '#{Inv} - #{Investor}'
  #   :name              => The file name you wish to give the document
  #
  #
  def export(action, args)
    set_action(action)

    if args[:records] == :all
      1.upto(record_count) do | record |
        export(action, args.merge(:records => record))
        @@word.word.ActiveDocument.Close(0)
      end
    else # For all other possibilities
      goto(args[:records])
      export_current
      save(args) if action == :save
      Document.new(:document => @@word.word.ActiveDocument)
    end
  end

  def save(args)
    location = create_directory(args[:path], args[:directory_formula])
    
    url = System::String.new(File.windows_join(location, args[:name]))

    puts "Saving: #{url}"

    case
    when args[:name].downcase =~ /\.pdf$/ then save_as_pdf(url)
    when args[:name].downcase =~ /\.doc$/ then save_as_doc(url)
    else
      raise "Don't know how to save: #{location}"
    end
  rescue Exception => e
    raise WordErrors::CouldNotSave, "Error saving to #{location}\\#{args[:name]}", [e.to_s] + e.backtrace
  end

  #
  # Holder for an array of all the data fields in the DataSource
  #
  def data_fields
    @data_fields ||= return_data_fields
  end

  #
  # Returns the number of records in a DataSource
  #
  def record_count
    @document.MailMerge.DataSource.RecordCount
  end

  #
  # Returns the Row Value for a Particular Column of the
  # DataSource
  def field_value(index)
    index = data_fields.index(index) + 1 if index.is_a?(String)
    @document.MailMerge.DataSource.DataFields(index).Value
  rescue
    raise WordErrors::NotMailMerge unless mailmerge?
  end


  #
  # Pass in a formula for fields and it finds and replaces the fields
  #
  def replace_fields_with_values(formula)
    while formula =~ /\#\{([^\}]+)\}/ do
      replaced_string = $&
      escaped_string  = field_value($1)
      formula.gsub!(replaced_string, escaped_string)
    end
    formula
  end

  def save_as_pdf(url)
    @@word.word.ActiveDocument.ExportAsFixedFormat(url, Microsoft::Office::Interop::Word::WdExportFormat::wdExportFormatPDF)
  end

  def print(args = {})
  copies = args[:copies] ? args[:copies].to_i : 1
  document.PrintOut(false)
  end

  private
  #
  # Creates the Directory to the current record based on the
  # path created by the directory formula
  #
  def create_directory(path, dir_formula)
    dir_name = directory_name_from_formula(dir_formula)
    dir_path = File.windows_join(path, dir_name)

    FileUtils.mkdir_p(dir_path) unless File.exists?(dir_path)

    dir_path
  end

  #
  # actions = [:save, :print]
  #
  def set_action(action)
    document.MailMerge.Destination = case

    when action == :print then 1
    when action == :save then 0
    else
      raise WordErrors::InvalidAction, action
    end
  end

  #
  # Performs the current action as setup by other variables.
  # Including set_action.  This action will only be used with
  # the :save action, since print automatically prints records
  #
  def export_current
    document.MailMerge.DataSource.FirstRecord = current_record
    document.MailMerge.DataSource.LastRecord = current_record
    document.MailMerge.Execute(false) # false is whether to "Pause"
  end

  #
  # Generates a name for the directory based on the values from
  # the record and a formula given by the user
  #
  def directory_name_from_formula(dir_formula)
    dir_name = dir_formula.clone
    replace_fields_with_values(dir_name).gsub(/[^A-Za-z0-9\ \-\+\.\,]+/, "-")[0..64].strip
  end

  #
  # Returns an array of all the data fields in the DataSource
  def return_data_fields
    @data_fields = []
    1.upto(@document.MailMerge.DataSource.DataFields.Count) do | i |
      @data_fields << @document.MailMerge.DataSource.DataFields.Item(i).Name.strip
    end
    @data_fields
  end

  #
  # Returns the numeric value of the ActiveRecord
  #
  def current_record
    document.MailMerge.DataSource.ActiveRecord
  end

  def save_as_doc(url)
    @@word.word.ActiveDocument.SaveAs(url)
  end

end

Working to scrub the data of any domain specific content, then I'll post the full code. If you have any questions, please E-mail me, and I'll answer them.

Chris

Wednesday, October 27, 2010

T-Mobile's New G2 and Why You Should Know Math / Finance

I was looking for my wife a new cell phone, and ran across a math / finance problem.  Look at this screen shot:


For a math professor, like Dan Myer, it has all the information that is needed.  It poses questions, many of them:
  • Which plan is cheapest?
  • When does the 500 minutes plan become more expensive than the 1000 minutes plan?
  • Should I purchase the phone for $499 or $199 given the change to the plan values?
  • Is there another carrier who is cheaper?
  • . . .
The question I am going to deal with is, "Should I purchase the phone for $499 or $199 given the change in the in the plan values?"  For this experiment, I am going to use the Unlimited Minutes to test.

$499 + 79.99 * 24 is less than $199 + 99.99 * 24.  Therefore, I should purchase the phone outright on a math basis.

Given you could invest the difference at 2%, the differing NPV's are about $170 difference.  You're cost of capital for the contract is about 9% between the two plans.  The cost of capital is a differential IRR equation.  $-300 now, but $20 more per month over the next 24 months, which equates to 9%.

This figuring doesn't include the taxes and fees, which would presumably be higher on the $99.99 / month plan than the $79.99 / month plan.  Giving even more lee-way to purchasing the phone in the beginning.

Monday, October 25, 2010

Why Top Students Don't Want to Teach

Harvard Business Review recently sent out their "The Daily Stat" with the headline "Why Top Students Don't Want to Teach."  Of, course . . . I was hooked.  What amazes me is the difference between the questions "I would be proud to tell people I had this job" and "People in this job are considered successful": 60% versus 38%.  To me, they are the same questions.  "I would be proud to tell people I had this job" has a "correct" answer.  The correct answer is "yes."  "People in this job are considered successful" externalizes the question, and you get more honesty.

The teaching profession has a large public opinion gap to overcome.  When I was a teacher, I was told multiple times "I can't believe you are a teacher."  Have fun with the results:


http://link.email.hbr.org/r/QTSN/74I53/MSL8ID/XJ4N9/NBOSH/U1/h

Sunday, September 05, 2010

What do Students Need?

At any moment in a young person's life, he has something to talk about.  Being around young people is a study of Maslow's Hierarchy of Needs.  At any one point, a student needs to talk about items from many points allow the spectrum.

He could talk about friendship dynamics, school challenges, participation, pending life decisions, college, etc.  Many students at all socioeconomic levels struggle with the lowest of food, shelter, safety, and power.  Above are some "Leave it to Beaver" items higher in Maslow's Hierarchy of Needs.

Ironically, students have the least access to individuals whom they trust.  They can't talk to friends, or they may be made fun of.  They can't talk to parents, they are often enforcers of discipline.  They can't talk to church leaders because they will be sent to Hell.  As many questions and needs as students have, they don't have confidants.  Just as adults and business leaders need confidants, young people need people they can trust.

Students need confidants.  Productive confidants are parents, grand-parents, teachers, advisors, or older siblings.  Dangerous confidants are manipulative factions: other students, gangs, and mass-media.  If students do have access to good information, they will find the closest information.

As a teacher, my core belief is:  At any time, a student has something to talk about.  I gave time for students and listened.  When I left teaching, I realized: At any time, everyone has something to talk about.  Adults have compartmentalized these "things to talk about."

Friday, August 27, 2010

Asymetrical Information, Football, and a Rain Shower

Hudson and I arrived home from the Mountain Brook v. Shades Valley high school football game.  We were the only people at the game who were mostly dry.  The rest were soaked by a short rain shower during halftime.  How did we make it safely, and the others did not?  I'll explain it with the financial concepts of "imperfect information" and "asymmetrical information."

Setting


The game was turning into a blow out; Mountain Brook has a star receiver (#7) and a pretty good QB.  Shades Valley has a stud running back, but the offensive line couldn't block the eight people the defense rushed each play.  Hudson and I arrived with half the first quarter remaining.

By the time we arrived, the parking lot was full.  There were easily 3500 people in the stadium.  In financial terms, 3500 people were "long" the football game.  Of the people there, I saw one umbrella.  1 of 3500 people hedged the chance of rain.  Everyone else relied on wit and intuition to avert rain.

The Information


Shortly after we arrive, I notice there are no stars or moon in the sky.  The light from the football game bounced off the clouds.  Using my new purchased smart phone, I downloaded "The Weather Channel" application.  Compared to everyone else in the stadium, I held "asymmetrical information."


I had more information than my present environment.  From the information, I determined: it might rain and if it did rain, it would be a small-short rain shower.  Everyone held "imperfect information."  Without knowledge of the larger environment, they only knew it might rain.  Once it began raining, all they knew was "it is raining."  The masses couldn't make a decision to stay or go, run to the car, or find quick shelter.  Even if they made the right choice, it was with incomplete information.

My Decision


When the first rain drop hit my nose, I picked up Hudson and walked out.  I was the first person to walk out the gate.  Drops were falling sparsely.  I looked behind me to see 20 people following.  The other 3478 were betting on a few drops.

When I found the first good shelter, Hudson and I stopped.  It was the guard shack at Mountain Brook High School.  The guard shack would max out at 20 occupants.  As Hudson and I stopped, the rain picked up.  One lady with her son stopped, I told them "It will only be a couple of minutes."

As with markets, when the masses are long the football game and without hedges, there is only so much shelter available.  Had I bet on rain and it not rain, I would have missed the the half time.  My cost would have been the minutes I waited for it to rain.  That was the cost of my hedge.

We waited.


Their Decisions


The 3478 people at the football game did not make decisions until realizing, shortly, they would be uncomfortable.  Rain fell faster; not considered a soaking rain, it was a dowsing rain.  Everyone else knew "it is raining."  Everyone else made decisions based on the uncomfortable rain and the decisions others made.  Shelters were full, under the trees was beginning to soak, and most people were running to their cars.

Everyone was making the best decision with the information he had.


Similarity to 2008


Beginning in 2005, certain people looked outside the bull market, i.e. the football game.  They began making their decision to leave the market.  They figure out how to short the market.  At the football game, these people would have brought umbrellas and sold them during the rain storm.  No one was that prepared.

In late 2007, other individuals began leaving the market.  They had seen the future, and had made a decision based on risk.  That was me.

In September and October 2008, that was the other 3478 people in the stadium.  Shelters were full with the early movers.  These individuals had two options: go to their car (sell and leave) or wait it out (take the pain).


Could I Have Sounded the Horn


Just because I was dry, doesn't mean I will always be dry.  Just because others were wet doesn't mean they will always get wet.  My information could have been incorrect.  Meteorologist (read professionals) see the same information I saw, and get it wrong 50% of the time.  I could have lost the cost of my hedge (i.e. the time to run to the guard shack).

Why didn't I tell everyone it was about to rain?  Correct decisions always look more correct when looking at them from the future.  Wrong decisions look like they could have been averted.

Thursday, August 26, 2010

Few Things are Better Than Running with my Son

For the last 3 weeks, I have made it a point to run more often.  After the 3rd time running the first week, Hudson said "I going."  I pulled out the jogging stroller and we ran.

He asked me questions about smaller objects we would pass in cars without noticing.  In the morning, we talk about the beauty in the sky.  I've taken him to an overlook near our house and looked at the rolling hills.  He points out dogs, leaves, birds, cars, and drains.

This morning, we ran to a local park to have breakfast: apples and yogurt.  He insisted on doing push-ups with me.  I drew an awkward cat; he drew a good looking ant, including dirt.  I played "Firehouse" with him.  We sprayed out fires.  Afterwards, I asked him if we should go look for victims.  He said, "They are at the victim store."   Once we got to the play structure that was "the victim store," he proclaimed "they have so many victims."

He and I have done different events together, and we get in streaks of fun.  Well run for a couple more months until it is too cold to run outside.  Then, we'll find another streak of fun.

Wednesday, August 25, 2010

Ah. . .the Start-up

When people ask what's it like to be at a startup, I give them a metaphore.

At my previous job, I was given a coloring book. It was my responsibility to draw between the lines. Everything between the lines was my responsibility. I could make it however I liked, but I had definite limits.  If I messed up on one page, we had the resources to turn the page.


At the startup, I have a blank canvas.  Should I mess up the canvas, we don't have the resources to purchase another.  But, should we not complete the canvas as to fulfill the market demand, we will be defeated by competition.


This week, John Mauldin wrote "The Importance of Start-ups."  He spoke about the statistics of job creation and innovation.  I am more interested in the "Why."  What are the motivational factors associated with startups?

Human Capital Input

At a corporation, my individual contribution was unseen because I was apart of a whole.  My role within the organization was largely unseen from the whole.  Or, my poor performance could be subsidized by a better employee.  At a corporation of 1000, I am 0.1% of the corporate human capital input.

At a start-up of 8 people I am 12.5% of the corporate human capital input.  Therefore, waste in that 12.5% is seen quickly.  One person failing at a start-up will cause a noticeable failure.


Urgency


Ever seen Lord of the Rings?  Start-ups are Frodo, corporations are the Eye of Soromon (not in a good v. evil sense, but due to power and resources).  The start-up runs quickly gathering customers without attracting the gaze of the corporation.  However, certain actions a start-up takes runs the risk of attracting the attention of the larger corporation.  This hyper competition felt by start-up causes them to run fast and even at night.

Individual Urgency


Nothing motivates the individual like the statement "If I don't perform, I won't be here next year."  The company may be here, the technology may be here, but I won't.

Hyper Capitalism


A start-up is capitalism at it's core.  A new company must perform all business functions to the level required, no more, no less.  If the company wastes resources, it will be gone.  If the company doesn't attract customers, it's gone.

It is capitalism at it's finest.

Tuesday, August 24, 2010

Learning is Controlled Confusion

As a teacher, I prided myself on teaching the highest level of content. I taught past the last comprehension of a student in my classes. My philosophy on learning is: I learn when I address an idea I've not previously encountered. Therefore, learning begins with confusion. As part of the learning process, a student must learn to be confortable with confusion, and logically progress to a point of knowledge.

When presenting information, I presented it from many angles; however, if a student did not understand, I was "okay" and I moved on with the lesson. On any given day, a student may or may not be prepared to listen and work. I assumed the first students would fall off the lesson at 30% of concept, and the best student would depart at 85% of the content. The majority would understand 65% of the content. I expected my "student understanding level" to be a bell curve.

Just was the students grouped together in the middle of the content, I used the most time on the middle content. I did teach to 100%: the final 10% were high level topics, and the final 5% were key terms. The beginning 15% percent was quick review.

Exposure to higher level information sparks the students mind, and potentially fixes unresolving issues on the lower level information.

I encourage all teachers to teach students to be "okay" with confusion. It is the personal state which causes the most growth. The true power of knowledge is not knowing the answer, but finding the answer.

Monday, August 23, 2010

Why I Love and Miss Teaching

From 2004 to 2006, I taught high school.  The courses I taught were

  • Business Law - Contract, Tort, Criminal, Personal, and Agency Law
  • Interactive Multimedia Design - Image, Video, Audio, Print Editing
  • Business Software - MS Office Suite, Word, Excel, Access, PowerPoint
  • Entrepreneurship - Students won second in state competition
  • Web Design - Everything about web design
What I Loved About Teaching

The first lesson in Business Law I had planned for 3 months: origins of law.  I discussed ethics, morals, religion.  Students looked in awe as I crafted my argument.  It was a magnificent lesson.  At the end of the day, a student said, "You made me think."  When hearing that, my inspiration to achieve soared.

As a teacher I learned my passion: challenge people with what they need to hear.  Paint them a picture of their future, and push them toward it.  Tell them they can achieve it, give them a path, and hold them accountable to that goal.  I continue to employ this skill/passion as often as someone will listen.

What I Loathed About Teaching and/or Non-Essential Tasks

Each dislike I had for the education system derived from one problem: lacking constancy of purpose.  As a teacher, I claimed to be "stamping out ignorance in East-Central Alabama."  Often, I felt I was preparing students to conquer the world.  Occasionally, the thought crept in my mind, "the education system drives our economy by allowing parents to go to work for a full 8 hours per day," which turned me into a $32,000 babysitter.

Schools adopted bloated mission statements stating the duality of purpose.  Optimizing schools as knowledge centers and nurseries results in schools performing neither optimally.

Documentation causes paralises.  The shear act of documentation is a classical management style which does equate to good teaching.  In Sebastian Junger's War, he describes great garrison soliders as poor infantry fighters and great infantry fighters as poor garrison soldiers.  Essentially, you want to fight with a "hell raiser."  Good documenters are poor teachers; good teachers are poor documenters.  Since I considered my job to "provide the most holistic education possible to my students," I often turned in documentation at 11pm on the due date.


Since 1930, the education system has instituted 80 major initiatives (assuming 1 per year), yet has not removed a single one.  Education systems should prioritize their initiatives; then, formally retire items outside the top five.  Teachers receiving tasks, reading mission statements, or policies will find too many tasks to effectively provide.

What I Learned

Teaching young people at school is a unique environment: I was responsible for students who did not necessarily need to be there, or want to be there.  My "carrot" was an environment to grow and learn.  My "stick" was failing.  I believed the average grade was a 75, and students receiving an 'A' were exceptional.  The stick was as a sales commission: directly tied to performance.

Due to my belief in the values of Theory Y management, "the stick" was rarely used.  I learned students wanted to learn.  I learned students wanted attention for performing outstanding work.  I learned students are complicated human beings: the 96% of their time outside my class affects my class.  Positive progress in my class can affect the other 96% of their time.  Students want to feel people are supporting their growth.  Someone is watching and waiting for them to achieve.

As convicted as I am with Theory Y, I learned it is tougher.  Organizational culture drive performance and unspoken rules.  However, once students agree, they support the system for growth.  Students eventually support each other and push growth.

Part of "the stick" was behavior correction.  As young people are apt to do, they wanted to assert their place in my class.  I prided myself on knowing what was "good", "okay," and "wrong" actions.  The "good" I praised, the "okay" I kept a check on, and the wrong I fixed quickly with a sharp rebuke.  I learned to discipline a student whom I genuinely liked.  I eventually considered discipline a core component of helping these young people grow.

Lastly, I learned to love public speaking.  As I stand in front of people I feel the room, watch their responses, and tailor my message.  Given bodily responses, I can determine who is interested, who would like another method of explanation, and who would never accept my message.   I learned to speak with authority, and accept questions on the fly.   Even if every prop I had planned is failing, I learned improv.  One day, electricity was halted; we discussed the philosophy behind our work.

Why I Quit Teaching


In the end, I quit.  I have various excuses, but none satisfy me:

  • My wife wanted to stay at home with the future kids, which she couldn't do on a teacher salary.
  • My next step was to get my MBA.
  • I was burned out on teaching 8 hours per day, and documenting the other 2 hours per day.

My passion for teaching waxed and waned as often as I felt the grass was greener in the business world. Lot's of folks around me seemed to put bugs in my ear about my potential outside the classroom.  In 2004, going the public school teaching route with a degree in Business Management looked like my career had crashed on take-off:

  • My professor/mentor, Dr. Hamilton, looked visually disgusted when thinking of my decision.
  • While I was walking with a student, he said, "Mr. Winslett, I would expect you would be doing something more."
  • My father, assuming I should feel sinful for what he was about to tell me, said, "You know you are being paid with tax money right."
  • Even today, my quick description of the decision to take the teacher job is "They were the first organization to say 'we will pay you to spend your days here.'"

While I was teaching, most everyone was shocked I was teaching: except me.  However, the eventual push of my perceived under-performance was too much: I jumped off a hedge fund to complete my MBA.


Completed Circle


My passions for work are: business, technology, and education.  Now, at GradesFirst, I am realizing each.  For me, business is a team of individuals accomplishing one goal via many motives.  When I see technology, I see good business practices.  Education is the largest of the three: it is where the world changes.  Business is the local team; technology is the method; and education is the output.  We at GradesFirst produce change in people's lives.

Saturday, August 21, 2010

How to "Save" Birmingham, Alabama, Part I

Step 1:  Realize Birmingham doesn't need "saving."

The metropolis area of Birmingham does not need to be saved.  It needs to be celebrated.  Birmingham looks at faults longer and harder than it celebrates successes.  Focusing on faults results in decisions taken to minimize failure instead of maximize return.

When I was a younger whitewater paddler, an older man told me, "When paddling through a rapid, focus your eyes on where you want to go.  Never look at where you don't want to go."

Each action creates a different mindset: paddling by focusing on failure causes you to mitigate risk.  Paddlers will be more likely to abandon the "best" route, and attempt to navigate a poor route.

Paddling by focusing on success causes you to do what it takes to hit the mark.  Instead of abandoning the route, you choose your route more precisely, and work like hell to get there.

Perhaps, the reason Birmingham focuses on failure is: it doesn't know where it wants to go.  When all choices are judged as negative, the decision is always to minimize failure.

`Would you tell me, please, which way I ought to go from here?'
`That depends a good deal on where you want to get to,' said the Cat.
`I don't much care where--' said Alice.
`Then it doesn't matter which way you go,' said the Cat.

`--so long as I get somewhere,' Alice added as an explanation.
`Oh, you're sure to do that,' said the Cat, `if you only walk long enough.'
Alice felt that this could not be denied, so she tried another question. `What sort of people live about here?'
`In that direction,' the Cat said, waving its right paw round, `lives a Hatter: and in that direction,' waving the other paw, `lives a March Hare. Visit either you like: they're both mad.'
`But I don't want to go among mad people,' Alice remarked.



Step 2:  Laugh

Our good friends at View of the City (http://viewofthecity.net) handle this.  It's essential we don't take ourselves so seriously.

Step 3:  Failure is Not the End

Unless you make it the end.  Out of failure arises the knowledge that the sun will rise tomorrow.  When paddling, the key purpose is to "not swim;" i.e. come out of your boat.  When learning to paddle, I always paddled better after I swam.  I'd seen failure, and I got back in the boat and tried again.

Friday, August 20, 2010

My Distorted Meaning of Happiness

The following article is based on the following assumptions:
  • Everyone likes to learn, work, and progress
  • Everyone wants a job they feel completes them
  • Everyone is smart enough to examine oneself
A Sad Life

The recession has uncovered flaws with companies and individuals.  Companies with bloated systems, failing markets, and those lacking direction have been wiped out.  Individuals with bloated systems, failing markets, and those lacking direction have been wiped out.

Let me describe the individual with the worst prospects in the current economy, I'll call him "John" and the company "SouthTrust":
  • John graduated college
  • John started working at SouthTrust when he was 22
  • John is now 48
  • John is middle management at SouthTrust
  • John knows middle management
  • John earns $90,000 / year
  • John spends $90,000 / year
  • John hasn't made a key decision for the company in 18 years
  • John hasn't talked to a customer in 18 years
  • John hasn't talked to someone else doing his job in another company for 20 years
This fabled "John" stalled.  There was an illusion of success long ago, but now it's escaped.  John has the same faults as companies currently failing: he's bloated, failing, and lacking direction.

That's the saddest image I could imagine: John blew away his options.

John's Faults

Pop quiz: what enables the greatest happiness?  Options.
Pop quiz: what makes people the happiest? Exercising options which enable someone to learn, work, progress, and explore.

John, whom I described above, has no options.  He can't transfer his skills easily.  He has to keep his current job: his lifestyle depends on it.  He limited his options by stagnating professionally.  He limited his options by structuring his life to require he continue to work.  He limited his options to change.

The Happy Life

The happy life would structure life to maximize options.  

Money

Receiving cash creates options.  Spending cash reduces options.  Creating debt (i.e. using your credit card) reduces your future options more than spending cash.  Creating an expensive lifestyle reduces options.

Knowledge

Learning creates options.  Being a master of a field creates options.  Practicing your knowledge creates options.  Sitting on your ass playing video games reduces options (what. . . really? If you want to know why, look at "Time.")

Knowledge creates more options than does money.  That's why parents are so willing to send children to college.  The $40,000 spent for knowledge is more valuable than the money.  Why do you think colleges raise tuition, yet people continue to attend?

Time

Since time only goes in one direction, each day that passes reduces options.  You have time in your life to do one less thing.  Of all the things you can change, this is the one that should ring your bell.  You can change this: it's called "now."  Do you want to make a change?  Make it now.  Then only good choice is  one that increases your options now.

Networking

People connecting with others creates options.  Connections are as valuable as knowledge and time.  Companies pay good money for connections.  Please pay good money for connections.

Summary

When making a decisions on your actions, choose the one creating the most options.  Look far enough in the future, and look out for cul-de-sacs in your decision tree.  John, above, reached a cul-de-sac.  His next decision creating the greatest number of options is to go back the way he came.

How is Automobile Traffic Like Financial Markets?

Automobile traffic like financial markets? One concept: arbitrage.

In finance the concept of arbitrage keeps markets fair. Given two farmers' markets in your town with different prices, Pepper Place and Alabama Farmers markets (two real farmers' markets in Birmingham, AL), farmers and buyers will ensure prices are equivalent. Given a perceived similar tomato, it should cost the same at either market. Market participants are smart, and they will create balance. Sellers and buyers at either market will move quickly to the other if they can get a good price.

Market participants participating in arbitrage ensures these markets are balance. Non-farmers could make money by purchasing at one market and selling at another.

In Birmingham, AL, traffic runs south through multiple channels: I-65, US 280, US 31, and AL 52. Given no traffic, everyone traveling to Montevallo, AL (25 miles) would travel I-65 and arrive in 20 minutes (70 MPH). Given stalled traffic on I-65, the next person starting in Birmingham going to Montevallo would travel US 31.

Consider different paths as different markets. Instead of tomatos, the highways sell transportation, and their price is travel time. As with costs for commodity products, people minimize their costs. For the average person with the average knowledge of the market, he cannot travel quicker than average using any of the four methods. For the person with the highest level of knowledge about the different markets, he can expect to travel faster regularly.

Information Reduces Cost

As with financial markets, real time information creates advantages on the road.  Googles realtime traffic information creates advantages for people to take advantage of arbitrage.  Any driver can determine travel time on one route, shorten exposure to that route, and lengthen exposure to another route.

Capital Asset Pricing Model

The Capital Asset Pricing Model is: for more risk, you would receive more reward, or it is a poor decision.  Each level of risk has an optimal reward, anything less than the optimal reward for a level of risk is a poor decision.  In Birmingham, you could go North to get South, but I'd expect the South-bound systems to be dead still.  That would be a scenario of taking extreme risk with an attempt to have a greater reward.  The more logical path is to wait as the South-bound systems to free up.

The System

For the average level of risk, you can't expect to do significantly better or worse than the system.  Within any system, rewards are a function of the system.  In a car, traveling to Montevallo from Birmingham, travel time will never be less 20 minutes.  Any stoppage will always cause exponentially greater travel time from the average.  Therefore, for the average person, choosing a path different than the interstate is useless, and don't expect to get there faster than the internet.

Why Buses are Useless for Mass-Transportation

This begins my thesis: buses are a waste of money for mass-transportation.  I'm not talking about transporting lower economic classes: for that buses have their place, but they still suck.

If everyone rode buses one day, then no cars would be on the road.  Seeing no cars on the road, most people would drive their car the next day.  Eventually, the market for transportation (i.e. the interstate) would balance.  Buses as mass-transportation are useless because they are a function of the same system: the highway system.

Trains are apart from the highway system -- though not without fault.  Given a dual track system, they offer a "benchmark" for interstates.  If a train takes 30 minutes (no matter what) to travel from Birmingham to Montevallo, then the train should make the average travel time on the highway 30 minutes.

Each South-bound travel method, the four highways and one train route, would equalize overall travel market.  However, the one train route would have the greatest affect because it is apart from the other linked systems.

Tuesday, June 29, 2010

3rd Week at a Start Up

I've discovered an indirect correlation between my waking early in the morning and events going as planned.  At the end of the first week, I'd developed my goals, a plan, and my timeline.  Having these three things together, I slept easier.

My goals, much like Obama's, revolves around the first 90 days.  My effort will go toward making significant change quickly.

My Goals


90 Days

  • Review and update as a team our development systems
  • Complete a reporting solution
  • Update website to a CMS
  • Sell to the University of Montevallo (alma mater)
My Plan

Make it through the first 90 days, start on next 90 days.

My Timeline

Bust it for 90 days, readdress after 90 days.

Saturday, June 05, 2010

Starting Up at a Start-up

Last week, on May 31st, I began anew at a start-up. Prior to taking the position, I performed due-diligence on the company and myself. What I anticipated was accurate. It is 3am. I woke up at 12:30am thinking about business.

When thinking about my new role prior to accepting, a new weight of business hit me: I will be responsible to the livelihood of others. In business school, I'd heard entrepreneurs discuss the responsibilities of making payroll. Turn it over in my head, I never felt the empathy associated with that level of responsibility. When I had the thought, I felt the responsibility of it.

In my prior position, I was 1 of 225 employees. Essentially, I was 0.4% of corporate output. If I was missing, 99.6% was there to fill the gap. My position was a cost defensive position: I protected against rising costs of business processes. I was neither responsible for revenue, nor strategy. However, what I was responsible for, I nailed.

Now, I am 1 of 9 employees. 10% of total business output. In some roles, I'm as high as 100% of corporate output. My actions are directly responsible for revenues today, next month, and the next month. All decisions are a precedent for the company.

Being early Saturday morning of my first week, this is not the first time I've woke early: it's the 5th. As proposed by legions of thinkers, when I sleep, my brain goes into "fix" mode. My brain is working to get things in order as it sees it. Of course, the best rest is to wake and actually get those in order.

And with that, I'm off to work.

Friday, February 26, 2010

Migrating to Postgres from Microsoft SQL Server with a little Ruby on Rails

Recently, I stopped the research phase of a business process project, and started the development phase. Out of research, I had determined using Ruby on Rails with JRuby and JDBC would be the best bet for interoperability with the current infrastructure. The current infrastructure consists of a enterprise level CRM running on SQL Server with .NET. The project would create a dataset which received CRM data. I chose SQL Server for this project to minimize complexity – one database engine.

For those interested, the following is how to connect to a SQL Server from Ruby on Rails using JRuby and JDBC. Be sure to download and drop the sqljdbc4.jar into your JRuby lib folder.


development:
host: cwinslett-475
adapter: jdbc
database: db_name_development
username: myuname
password: mypword
driver: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: jdbc:sqlserver://myserveripaddress;databaseName=db_name_development


The Last Straw with SQL Server – Pagination

Take a look at the following:


SELECT * FROM (SELECT TOP 20 * FROM (SELECT TOP 20 * FROM contacts ORDER BY contacts.last_name, contacts.first_name) AS tmp1 ) AS tmp2


This is SQL Server’s solution for pagination. That is ugly, but fine. However, pagination returns an odd number of rows when performing joins. The following is the SQL:


SELECT * FROM (SELECT TOP 18 * FROM (SELECT DISTINCT TOP 18 investments.id FROM investments LEFT OUTER JOIN authorized_contacts ON (investments.[id] = authorized_contacts.[investment_id]) LEFT OUTER JOIN contacts ON (contacts.[id] = authorized_contacts.[contact_id]) WHERE (authorized_contacts.is_primary = 1) ) AS tmp1 )


The Solution – DataPumper

Also known as SQL work Bench (http://www.sql-workbench.net/) , it’s the easiest way I’ve found to migrate from SQL Server to Postgresql.

I arrived at it after trying the built in “Export” feature in SQL Server Management studio, but it failed with the Postgresql ODBC. I performed any 45 minutes of searches and finally arrived at DataPumper.

When I downloaded it, I fired up the GUI. I pointed it to my SQL Server CRM database. Worked like a champ after pointing to the JDBC files for the databases.

Integrating with Ruby on Rails

I now use DataPumper for my “rake db:seed” task. I needed production data for my environment, and when I deploy, I’ll need the same data. First step was setting up my export schema. I created a file with all my tables (db/development_import):


WbCopy -sourceProfile='My SQL Server Profile'
-sourceGroup='Default group'
-targetProfile=’My Postgres Profile’
-targetGroup='Default group'
-targetTable=addresses
-sourceTable=dbo.addresses
-columns='description/description, address/address, address_2/address_2, address_3/address_3, address_4/address_4, city/city, province/province, postal_code/postal_code, country/country, is_primary/is_primary, is_mailing/is_mailing, id/sql_server_id, contact_id/sql_server_id'
-deleteTarget=false
-continueOnError=false
;
WbCopy -sourceProfile='My SQL Server Profile'
-sourceGroup='Default group'
-targetProfile=’My Postgres Profile’
-targetGroup='Default group'
-targetTable=contacts
-sourceTable=dbo.contacts
-columns='prefix/prefix, last_name/last_name, middle_initial/middle_initial, first_name/first_name, suffix/suffix, company/company, phone_work/phone_work, phone_home/phone_home, phone_other/phone_other, email/email, email_2/email_2, email_3/email_3, authentication_string/authentication_string, id/sql_server_id, formal_salutation/formal_salutation, fax/fax'
-deleteTarget=false
-continueOnError=false
;


Then I copied the sqlworkbench.jar to db/ sqlworkbench.jar. Then I configured db/seeds.rb:


`java -cp db/sqlworkbench.jar workbench.WbStarter -script=db/development_import`


Now, when I run “rake db:seed” it will fire off the data migration. When I run “rake db:reset” I get a clean DB with fresh data.

Data Clean Up

In my data migration above, I map the Primary keys from SQL Server to another field, because I want Postgres to handle its own Primary Keys. I added this to the end of my db/seeds.rb:


ActiveRecord::Connection.execute(“UPDATE addresses
SET contact_id = contacts.id
FROM contacts WHERE contacts.slx_id = addresses.contact_slx_id;”)


Data Migration Gotchas

Data types will hurt here. Database data types are not standard. Even if databases had the same data types, application developers use different conventions. Above, in my DataPumper configuration, I use “-sourceTable.” However, the “-sourceTable” is actually a view I’d created to use with Rails. I had already done data type variable casting to get boolean types. I did this with the following in my SQL for the view, notice the inline (CASE WHEN THEN statements):


SELECT ADDRESSID AS id, ADDRESS1 AS address, ADDRESS2 AS address_2, CITY, STATE AS province, POSTALCODE AS postal_code, COUNTRY AS country, ADDRESS3 AS address_3, ADDRESS4 AS address_4, ENTITYID AS contact_id, DESCRIPTION, CASE ISPRIMARY WHEN 'T' THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS is_primary, CASE ISMAILING WHEN 'T' THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS is_mailing FROM dbo.ADDRESS