Dispatches from Techistan

As a programmer here in the heart of Techistan (a.k.a. Silicon Valley), I often get blind recruitment emails, many of which are unintentionally entertaining (recommended anyone interested in this particular topic should follow Shit Recruiters Say [@recruiterbro] on Twitter). Today’s was from a startup called Clinkle (rhymes with Tinkle), famous for being hacked before launch as well as their executive staff of former Netflix bigwigs, one of whom is described in this TechCrunch piece as a “get shit done guy”. The article goes on to mention that this executive is mostly known for his role in Netflix’s biggest fiasco, the “Qwikster” spinoff, where they tried to raise prices in return for less service while splitting your one account into two separate accounts for no apparent reason. One is tempted to take the term “get shit done guy” in the literal sense of “when he does get things done, they are shit.”

Even in this modern hipster world, it’s hard to believe that a CEO will freely use the word “shit” to praise his new VP of Operations! But the headlines never cease for this company. Here’s a good one:

Payments Startup Clinkle Lays Off A Quarter Of Its Staff [UPDATED: New Layoffs In Addition To 30+ Who Already Left]

Oh, and

Leaked YouTube Video & Tumblr Blog Reveal All About Stealthy Payments Startup Clinkle

The latest being this one from a couple of weeks ago:

Clinkle Gets Hacked Before It Even Launches

I feel sorry for the recruiters who must realize that any interested recipients of their emails will naturally check out the company they’re representing, especially when the subject line of the email is:

Exciting Opportunity at Clinkle!

Advertisements

Pytaf

My new open source project – PYTAF (Python Test Automation Framework) – is in the process of being announced on Freecode.com. The project can be accessed directly through GitHub. It’s a distillation of the various test harnesses I’ve developed over the past several years, beginning in Java, polished in Ruby, until finally fully formed in Python. This version is actually in Python 3, which I’m not using yet in everyday work. It’s not much different, but developing this project was partly a mechanism for learning about it.

I’m happy to put it out there in the world, as happy as putting out any of my ebooks or earlier open-source projects. If one person finds it useful, that will be ‘abundance’.

announcement also here on opencode

According to opencode’s automated project analyzer:
 Codebase 725 lines
 Effort (est.) 0 person-years
 Estimated Cost $ 7,847

Praystation is here (for your Android device)

Many years ago I had the (not terribly original) idea to write a smart-phone app that would simply consist of a green arrow pointing always towards Mecca. I would call it The Sunni Praystation (you get the joke, I’m sure). Well, fast forward to last night, when I realized I needed to learn more Android programming in order to do something for my job, and decided to actually write the darn thing. With much thanks for the Flying Spaghetti Monster as well as various blogs and Android Api documents, I can now present to you, in all its minimal glory, Praystation:

Don’t all applaud at once. Yes, I know, it needs some sprucing up … but next steps also include shoving it onto the Android Market as yet another free app (there are several much nicer looking ones that do the exact same thing, by the way. No patents pending here …)

Easy DIY CouchDB using Ruby

Rather than use somebody’s couch gem, (which may or may not return JSON when you expect it to!), what I’m doing here is rolling my own compact Couch library class in Ruby. The class simply uses net/ssh to make properly formed REST calls to the CouchDB. You also need the ‘json’ gem installed. (Also, I’m using Ruby 1.8.7)

The Couch class needs a host, port and db parameter passed into its initialize method. The db is the name of the db, while the host and port are used by the request method to form the URL.  Most every call to Couch is either a GET or a PUT (there is also a DELETE), so we only need a couple of methods (get, put) to create the right kind of Net::Http object, make the REST call and convert the Http response into JSON.

Here is couch_lib.rb

# begin code

require ‘net/ssh’
require ‘json’

class Couch
  def initialize(host, db, port=5984, options = nil)
    @host = host
    @port = port
    @db = db
    @options = options
  end

def request(req)
    res = Net::HTTP.start(@host, @port) { |http|http.request(req) }
    unless res.kind_of?(Net::HTTPSuccess)
       # if there was some kind of Http error, show it
       puts res
    end
    res
  end

def get(id, parse=true)
    res = request(Net::HTTP::Get.new(“/#{@db}/#{id}”))
    parse or return res.body
    JSON.parse res.body
  end

 def put(id, doc)
    req = Net::HTTP::Put.new(“/#{@db}/#{id}”)
    req[“content-type”] = “application/json”
    begin
      req.body = JSON.generate(doc)
      res = request(req)
      $DEBUG and puts “put response: #{res.code} :: #{res.body}”
    rescue
      current = get(id)
      doc[“_rev”] = current[“_rev”]
      req.body = JSON.generate(doc)
      res = request(req)
    end
    hash = JSON.parse res.body
  end

# here we have a method to create the database
 def create
    req = Net::HTTP::Put.new(“/#{@db}/”)
    req[“content-type”] = “application/json”
    res = request(req)
    JSON.parse res.body
  end

 # use clear method to drop and create a db
  def clear
    begin
      request(Net::HTTP::Delete.new(“/#{@db}”))
    rescue
    end
    req = Net::HTTP::Put.new(“/#{@db}/”)
    req[“content-type”] = “application/json”
    res = request(req)
    JSON.parse res.body
  end
 

end

# end code

To test the Couch class, I created a new database, put some data into it, created and stored some views, and make queries. The default parameters assume that CouchDB is running on localhost on default port 5984, but those are easily configurable.

# begin code
require ‘rubygems’
require ‘couch_lib’

$DEBUG = true

class CouchTest

  def initialize(p={})
     @params = { “host” => “127.0.0.1”,
                 “port” => “5984”,
                 “db” => “pwp”
                 }.merge! p
     begin
       @db = Couch.new(@params[“host”], @params[“db”])
     rescue => e
       puts(‘oops. is couchdb running at http://#{@params[“host”]}:#{@params[“port”]}?’)
       exit(-1)
     end
    
    # make pwp database
    make_pwp_db

    # make pwp-specific view
    make_pwp_views
   
  end

  def make_pwp_db
    puts “delete the existing db and create a new one”
    @db.clear

    unwritten = {“title” => “unwritten rules”,”date” => “2010”,”category” =>”urban fantasy”}
    sidewalk = {“title” => “secret sidewalk”,”date” => “2007”,”category” =>”urban fantasy”}
    renegade = {“title” => “renegade robot”,”date” => “2010”,”category” =>”urban fantasy”}
    zone = {“title” => “time zone”,”date” => “1999”,”category” =>”science fiction”}
    missy = {“title” => “missy tonight”,”date” => “2008”,”category” =>”atheist fiction”}
    @db.put(“unwritten”, unwritten)
    @db.put(“sidewalk”, sidewalk)
    @db.put(“renegade”, renegade)
    @db.put(“zone”, zone)
    @db.put(“missy”, missy)
  end

  def make_pwp_views
    titles_view = { “_id” => “_design/titles “,”language” => “javascript”,
      “views” => {
        “result” => {“map” => “function(doc) { if (doc.title) { emit(doc.title, doc)} }” },
        “all” => {“map” => “function(doc) {  emit(null, doc) }” }      
      }
    }

    dates_view = { “_id” => “_design/dates “,”language” => “javascript”,
      “views” => {
        “result” => {“map” => “function(doc) { if (doc.date) { emit(doc.date, doc)} }” }
      }
    }

   categories_view = { “_id” => “_design/categories “,”language” => “javascript”,
      “views” => {
        “result” => {“map” => “function(doc) { if (doc.category) { emit(doc.category, doc) } }” }
      }
    }

   @db.put “_design/titles”, titles_view
   @db.put “_design/dates”, dates_view
   @db.put “_design/categories”, categories_view
  end

  def delete_doc(doc)
    @db.delete(doc)
  end

  def get_all_items(sorted=false)
   # curl -X GET http://127.0.0.1:5984/pwp/_design/titles/_view/results
   puts “==> get all items”
   dataset = Array.new
   items = @db.get(“_design/titles/_view/all”)[“rows”]
   items.each do |row|
      dataset << format_item(row[“value”])
    end
    dataset.sort! if sorted
    dataset.each { | s | puts s } if $DEBUG
    return dataset
  end

  def get_all_items_by_date()
   puts “==> get all items by date”
   dataset = Array.new
   items = @db.get(“_design/dates/_view/result”)[“rows”]
   items.each do |row|
      dataset << format_item(row[“value”])
    end
    dataset.each { | s | puts s } if $DEBUG
    return dataset
  end

  def get_by_date(target=”2010″)
    puts “==> get by date: #{target}”
     dataset = Array.new
     items = @db.get(“_design/dates/_view/result”)[“rows”]
     items.each do |row|
      item = row[“value”][“date”]
      if item.include?(target)
        $DEBUG and puts JSON.pretty_generate(row)
        dataset << format_item(row[“value”])
      end
    end
    dataset.each { | s | puts s } if $DEBUG
    return dataset
  end

 def get_by_title(target=”e”)
    puts “==> get by title: #{target}”
     dataset = Array.new
     items = @db.get(“_design/titles/_view/result”)[“rows”]
     items.each do |row|
      item = row[“value”][“title”]
      if item.include?(target)
        dataset << format_item(row[“value”])
      end
    end
    dataset.each { | s | puts s }
    return dataset
  end

   def get_by_category(target=”e”)
    puts “==> get by category: #{target}”
     dataset = Array.new
     items = @db.get(“_design/categories/_view/result”)[“rows”]
     items.each do |row|
      item = row[“value”][“category”]
      if item.include?(target)
        dataset << format_item(row[“value”])
      end
    end
    dataset.each { | s | puts s } if $DEBUG
    return dataset
  end

  def format_item(item)
    return “title: #{item[“title”]}\tdate: #{item[“date”]}\tcategory: #{item[“category”]}”
  end

  def update_renegade
    puts “==> update renegade, change its category”
    renegade = {“title” => “renegade robot”,”date” => “2010”,”category” =>”science fiction”}
    @db.update “renegade”, renegade
  end

  def delete_renegade
    puts “==> delete renegade”
    r = @db.get(“renegade”)
    @db.delete(r)
  end
 
end

# usage example: ruby couch_test.rb host=localhost port=5984

if $0 == __FILE__
   params = {}
   ARGV.each do|a|
     args = a.split(“=”)
     params[args[0]] = args[1].chomp
   end
   db = CouchTest.new(params)
   db.get_all_items(true)
   db.get_all_items_by_date
   db.get_by_date(“2010”)
   db.get_by_category(“science fiction”)
   db.get_by_title(“secret”)
   db.update_renegade
   db.get_by_category(“science fiction”)
   # db.delete_renegade
   # db.get_by_category(“science fiction”)
end

# end code

gb

messing around with GarageBand this morning I realized that this was the program I really wanted when I started getting into computers back around 1987 (coincidentally, the last time the SF Giants faced the current predicament of being up 3-2 in the NCLS but on the road, eventually to lose both games. please not again!) – computers attracted me for music reasons, which is why i began with an Atari ST (it had built-in MIDI ports) and why I taught myself computer programming. I ended up getting a college degree in music engineering and went to work for a music software company, but the stuff that was available back then could only aspire to GarageBand simplicity and ease of use. There was a lot of great stuff (ProTools, StudioVision, MOTU, etc …) but this application really has what the average user needs.