Tuesday, July 23, 2013

Using 3rd-party Erlang modules in Elixir


Calling into other people's Erlang from Elixir is pretty straightforward, but there are a couple things to be aware of. Let's start with some sample Erlang code that uses the epgsql module.


-module(pgdemo).
-compile(export_all).

-define(EPG_PATH, "/Users/alh/src/epgsql/ebin").

main() ->
    setup_paths(),
    {ok, PGConn} = pgsql:connect("localhost", "dba", [{database, "users"}]),
    {ok, Columns, Rows} = pgsql:squery(PGConn, "SELECT * FROM auth_user").

setup_paths() ->
    code:add_patha(?EPG_PATH).
Here's the same code written in Elixir:


defmodule PgDemo do
  @epg_path "/Users/alh/src/epgsql/ebin"

  def main do
    setup_paths
    {:ok, pg_conn} = :pgsql.connect('localhost', 'dba', [{:database, 'users'}])
    {:ok, columns, rows} = :pgsql.squery(pg_conn, 'SELECT * FROM auth_user')
  end

  defp setup_paths do
    Code.append_path(@epg_path)
  end
end
So what's different?
  • Because the module naming conventions are different between Elixir and Erlang, Elixir imports Erlang module names as atoms, e.g. :pgsql
  • Again because of naming conventions, Erlang atoms like database become :database and a local variable like PgConn in the Erlang version becomes pg_conn in Elixir.
  • Most (all?) Erlang functions that take a string as an argument are going to expect that string to be a char list, a list of 8-bit values ... but a typical double-quoted string in Elixir is UTF-8! We need to single-quote string literals when they are arguments to an Erlang function. If you have a UTF-8 string stored in an Elixir variable, you can convert it to a char list with the binary_to_list/1 function. For more about Elixir strings see the Getting Started Guide section 2.3.

Also, there doesn't seem to be an exact equivalent in Elixir to Erlang's -define() for defining a constant. You can use module attributes (Section 3.6) for defining string constants and they will be inlined at compile-time.


Wednesday, January 04, 2012

A Concurrency Programming Kata in Erlang


Write an Erlang program that spawns two processes. Each process should:
  1. Send a unique (pseudo-random) key/value pair to the CouchDB database. Remember the value in-process so it can be confirmed later (see Step 6.) Don't use process dictionaries for this.
  2. Send the Id of the created CouchDB record to the other process.
  3. Listen for Ids being sent to it by the other process.
  4. On receiving an Id, retrieve the Id from CouchDB.
  5. Send the retrieved value back to the other process to confirm the retrieval is correct.
  6. Confirm any values sent to it by the other process. Don't re-fetch the record from CouchDB. Don't use process dictionaries.
  7. Sleep for an interval.
  8. Goto (1).
This kata helps us to explore Erlang's concurrency primitives, which are Erlang's best, most distinctive feature.

If you're using Homebrew on OS X:


~$ brew install erlang
~$ brew install couchdb
~$ couchdb # Will run in the foreground, switch to a new Terminal for the rest
To get started using Erlang to communicate with CouchDB you'll need a couple modules, installed like this:


~$ git clone git://github.com/ngerakines/erlang_couchdb.git ; cd erlang_couchdb ; make
~$ svn checkout http://mochiweb.googlecode.com/svn/trunk/ mochiweb ; cd mochiweb ; make
Here's some sample code to load the module paths, demonstrate the CouchDB API, and verify all of those pieces are working:


-module(kata_couch).
-compile(export_all).

% Path to your erlang_couchdb clone + "/ebin"
-define(ERLANG_COUCHDB_PATH, "/Users/alh/src/erlang_couchdb/ebin").
% Path to your mochiweb checkout + "/ebin"
-define(MOCHIWEB_PATH, "/Users/alh/src/mochiweb/ebin").
-define(DBSERVER, {"localhost", 5984}).

main() ->
    setup_paths(),
    db_demo(),
    init:stop().

db_demo() ->
    erlang_couchdb:create_database(?DBSERVER, "test1"),
    {json, {struct, [{_,_}, {<<"id">>,Cid}, {_,_}]}} =
        erlang_couchdb:create_document(?DBSERVER, "test1", [{<<"keyA">>, <<"valA">>}]),
    Retr1 = erlang_couchdb:retrieve_document(?DBSERVER, "test1", binary_to_list(Cid)),
    {json, {struct, [{_,_}, {_,_}, {K,V}]}} = Retr1,
    io:format("~p : ~p~n", [K, V]).

setup_paths() ->
    code:add_patha(?ERLANG_COUCHDB_PATH),
    code:add_patha(?MOCHIWEB_PATH).
And an idiomatic sleep/1 function, taken from the Armstrong book:


sleep(T) ->
    receive
        after T ->
            true
    end.

Wednesday, August 03, 2011

perlbrew and 32-bit CPAN modules like Mac::Growl


Today I discovered perlbrew, a utility for managing multiple versions of Perl under a non-root account, in the same spirit as rvm or virtualenv. I was forced into discovering perlbrew, because installing XCode 4 onto a Mac breaks the ability to compile many CPAN modules if you stick with the computer's default Perl.

Even with perlbrew, you might still have trouble compiling CPAN modules on a Mac, if those modules need older 32-bit code. This is because perlbrew doesn't build its perls as fat binaries, it builds them as 64-bit only.

I used perlbrew to install Perl 5.14.1, and then I was trying to install Test::Continuous, which has a long chain of dependencies including Mac::Growl, Mac::Growl itself depending on Mac::Carbon. Mac::Carbon is 32-bit. I was able to work around this, but I had to (temporarily) leave the CPAN shell to do it. The steps are:

  1. Install Cocoa::Growl as a 64-bit alternative to Mac::Growl. You can use the CPAN shell for this.
  2. Install Log::Dispatch::MacGrowl. This module will recognize that you
    have Cocoa::Growl installed, but for some reason it still won't install
    via CPAN shell. But it will install if you download the tarball and build manually.
  3. Now via CPAN install Log::Dispatch::DesktopNotification.
  4. Now via CPAN install Test::Continuous.

Friday, June 24, 2011

SEO changes forever (or so I've read)


But you have not, as SEOs, we never really had to think as much or as broadly about, "What is the experience of this website? Is it creating a brand that people are going to love and share and reward and trust?" Now we kind of have to think about that.

How Google's Panda Update Changed SEO Best Practices Forever

This, in a nutshell, is the problem I've always had with SEO. People have seen SEO as a bullet list of things to do, a checklist of fairly mechanical steps that, if you closely follow the steps, your page rank will go higher. I read the above as an admission that the SEO consultants themselves have (until now) viewed SEO the same way. I've had clients ask me if they should spend the money on a dedicated SEO consultant and my answer was always "ehhhhh..." Following the SEO checklist might move your page rank a couple spots, but if you want your site to rank substantially higher, you need to substantially change your site. If Panda transforms "SEO consultants" to become "user experience consultants" that's probably not a bad thing.

Thursday, June 09, 2011

Why Apple is charging you to store non-iTunes music in iCloud


If you own some music that you bought from iTunes and you choose to "upload" it into iCloud, you're not really uploading anything. Apple already has it. You originally bought it from them. They just have to store the fact that you are allowed to access their copy of the song. Six million people can "store" Poker Face in iCloud, Apple has to keep only the one copy. Us nerds call this single-instance storage.

On the other hand, if you ripped some music from a CD that you own, and you want to upload that into iCloud, Apple has to actually accept the song from you and allocate disk space to store it. That costs them money, and everyone knows that Apple doesn't do anything for free, so you can bet they're going to charge that cost back to you.

Thursday, April 21, 2011

Health insurance is more fun if you treat it like a game


> look
You are in a twisty maze of insurance forms, third-party authorities, and provider networks, all alike.
> file claim
You fill out a claim form for your wrist therapy and drop it in the mail.
> wait
Time passes...
> wait
More time passes...
> wait
Weeks pass. Your claim returns in the mail, rejected, with a brief explanation at the bottom.
> read explanation
The words are English, but somehow meaningless. As far as you're concerned, it could be written in Sanskrit.
> call insurance company
Home, auto, life, or health?
> health
I don't know how to "health".
> call health insurance company
The phone at the other end is ringing.
> wait
Time passes...
A mechanical voice answers. It explains that all operators are currently helping other customers, and would you like to leave a message?
> leave message
What would you like to say in your message?
> leave name and number.
You leave a polite message with your name and phone number.
> wait
Time passes...
You get a call from your health insurance company.
> ask about rejected claim
Which one?
> ask about rejected claim for wrist therapy
The operator explains that since you are a new customer, they need an explanation from the doctor's office assuring that this was not a pre-existing condition. A copy was sent to the doctor's office and as soon as they receive a response they will provide a benefit on your claim. You thank the operator and hang up.
You have a headache.
> wait
Time passes...
> check mail
There is a bill from the doctor's office in your mailbox.
> open bill
They want a prodigious amount of money. There is a notice at the bottom saying that they have not received a response from your insurance company.
You have a headache. You can feel a vein throbbing in your right temple.
> call doctor's office
A mechanical voice answers explaining that it is 12:30 and everyone is at lunch.
> leave name and number
You leave a polite message with your name and phone number.
You have a headache. The tension in your neck is constricting the flow of blood to your brain.
> wait
Time passes...
You get a phone call from the doctor's office.
> which one?
Don't get pedantic with me!
> ask about bill
She says they haven't heard from your insurance company. Therefore the full amount due is your responsibility to pay.
> read explanation from rejected claim
She seems to understand the explanation, but she says that she hasn't received a copy.
> pound head on desk
You slam your head against the desk several times. You feel dizzy, but most of the pressure is gone for now.
> take claim to doctor's office
You get in your car and start driving to the doctor's office. Unfortunately you must have broken a blood vessel when you were beating your head on the desk. Halfway there, your vision goes red and your car careens off the road.
You have died.
You obtained $0 out of a possible $5000 in benefits. Would you like to play again?

Monday, April 11, 2011

ImageMagick, Homebrew, the NEWS.txt error


Seems like everyone has trouble installing ImageMagick, but everyone has a slightly different problem. In my case I was getting the error:

Error: No such file or directory - /usr/local/Cellar/imagemagick/6.6.7-10/share/ImageMagick/NEWS.txt
To fix this, do "brew edit imagemagick" (or "sudo brew edit imagemagick" if that's how you brew) and find these lines:

# We already copy these into the keg root
%w[NEWS.txt LICENSE ChangeLog].each {|f| (share+"ImageMagick/#{f}").unlink }
and comment out that line of Ruby. Re-run "brew install imagemagick" and it should work.

Thursday, July 01, 2010

Visual Studio: My build actions are missing


Since this seems to be a faq without an answer: In Visual Studio 2008 (and earlier?) if your project files are missing their Advanced properties - like Build Action - it probably means you were handed a "web application" that is actually a "web site" in Visual Studio parlance. You have to create a new "web application", copy over the source files, and a few other steps to complete the conversion. Some relevant links:

VS 2005: Converting a Web Site Project to a Web Application Project in Visual Studio 2005

VS 2008: Converting VS 2008 Website to Web Application

VS 2010: Converting a Web Site Project to a Web Application Project

Friday, May 14, 2010

Adobe is becoming the Jay Leno of developer tools


Adobe needs to take a page from David Letterman: "You get fired, you get another gig! You go across the street and you punish them and you make them eat your words!"

Adobe is trying to leverage public opinion - and even government intervention! - by portraying itself as the victim of a monopoly power. They start with the assumption that the iPhone is the only gateway to the mobile web, and of course it's not. The high road would be to make a Flash runtime for Android that kicks so much ass that Apple has to change their stance or be left behind in the market. This duplicitous war of words is a low road, a beggar's stance. A Jay Leno move.

Wednesday, May 12, 2010

Uh, thanks Steam, I guess?


Steam said that my downloaded copy of Portal had a 303 million percent fragmentation rate? ... But then Steam defragged it for me, so it's 303 million percent better now.

Friday, April 23, 2010

Snow Leopard, external displays, and fonts


UPDATE 05/03/2010: The correct answer seems to be this one: 10.6: Re-enable LCD font smoothing for some monitors. "The problem with the Automatic option is that OS X incorrectly detects many third party LCD monitors as CRTs, and consequently, disables LCD font smoothing."

A couple months ago I purchased a new 13" Macbook Pro. This was before the April updates, so it's the mid-2009 model. As an external display I'm still using the BenQ FP202W that I've had since 2006. The MBP connects to the BenQ with an official Apple-branded MiniDisplay-to-DVI adapter.

I've boiled the weirdness down to a reproducible case:

(1) Open XCode. The editor screen looks like this:


i.e. it looks normal. Legible.

(2) Connect the adapter to the BenQ monitor and connect the adapter to the MiniDisplay port on the laptop. My desktop appears on the BenQ and XCode still looks normal.

(3) Quit XCode and restart it. Now the editor looks like this:


It's the same font (Monaco Regular 12) but the rendering is somehow different. Weak and spidery. The difference is noticeable in the screengrabs, in person the difference is even more jarring.

TextMate does the same thing. I have TextMate also using Monaco Regular 12, so maybe it's related to the font? I have no idea what's causing this or how to fix it.

Saturday, April 17, 2010

Interactive Debugger for PHP


If you're looking for a free (zero-dollar) debugger for PHP, I've stumbled onto the combination of Xdebug installed onto the server and MacGDBp on my workstation. My favorite part is that I don't need to have a copy of the source tree on my workstation to do source-level debugging. It's transferred to me on demand by the magic of DBGP.

UPDATE: If you don't mind dropping a little money, I've been happy with the debugger in PHPStorm. You still need Xdebug installed on the PHP server for PHPStorm to interact with it.

Wednesday, January 20, 2010

The Nerd in the High Castle


I like to read history books, and that includes the history of the computer industry. Steven Levy's stuff is pretty good, even if sometimes he gets a little breathless in the telling. Dealers of Lightning, West of Eden, Soul of a New Machine, stuff like that.

From reading enough of these, and from the tech press as well, I know there's this notion floating around that during the early 80s Apple was fighting the wrong enemy. (Pirates of Silicon Valley also plays this note.) During that era, Apple focused on IBM instead of on Microsoft. But Microsoft and MS-DOS really won their independence from IBM during the Clone Wars. Everyone wanted to clone the IBM PC, and run MS-DOS on it, because IBM had been so successful. If Apple had somehow won market dominance over IBM in the early 80s, they would have also defeated Microsoft by proxy.

That got me thinking though, that Microsoft probably would not have stayed out of the OS market. They were still a successful applications company at the time and, if PC-DOS had failed, they surely would have made another attempt at an OS product. Now it starts to sound like the plot of a alternate history novel, doesn't it? On the back cover: "What if Apple had defeated IBM in 1984? What if Microsoft had partnered with Commodore to sell MS-Windows in 1986?"

Wow I just realized... if someone wrote that book, I would totally read it.

Wednesday, October 14, 2009

Can I make a UIView transition to itself?


Sure, why not?

Let's say you have a UIViewController and you want the base view to do a CATransition from itself to itself:

- (void)doTransToSelf {
    CATransition *anime = [CATransition animation];
    anime.type = kCATransitionPush;
    anime.subtype = kCATransitionFromRight;
    anime.duration = 0.5;

    UIView *mySuper = self.view.superview;
    [self.view removeFromSuperview];
    [mySuper addSubview:self.view];
    [mySuper.layer addAnimation:anime forKey:nil];
}


Or, changing this to work on a subview of self.view is trivial.

So, why would you want to do this? In my case, I have a collection of data objects and a UIView that is the user interface for editing one object. When the user is ready to move on and edit the next object in the collection, the user interface doesn't substantially change, I'm really just changing the data object that is the target of the user's edits. So I want to re-use the same view with the same set of IBOutlets, and just do the transition as a visual cue to the user - "okay, you're working on a different object now."

Sunday, June 28, 2009

Why won't my backBarButtonItem use its action?


Or, How to make a backBarButtonItem send its action to its target.

Answer: you don't.

Because a backBarButtonItem is a UIBarButtonItem, it has "target" and "action" properties, leading you to believe that if you assign values to those properties, shit will happen. Alas, shit will not happen. Or rather, the usual shit will happen, but not the extra shit you hoped would happen. The backBarButtonItem is special - no matter what you do with those properties, «target» will never receive a message for «action».

What you can do instead is assign a delegate to either your UINavigationController or UINavigationBar. Both of these classes have delegate protocols that give you opportunities to act when the stack of view controllers changes. I've been using my root view controller as the delegate object, since that one never gets popped off the stack.

Friday, May 22, 2009

Sun. Oracle. Ponytails.


So... Sun. Oracle. And of course Schwartz. Schwartz, Schwartz. Blogging his way through the graveyard, chanting his open source mantra. As if clinging to all the right buzzwords would make up for not having an actual strategy. "I'm a CEO with a blog! How can my company fail??"

There are lots of companies that get by without a strategy, at least for a while. Hell, I used to work for one. But if you're going to get into the business of being a VAR for a product (free software) whose starting cost is zero and whose cost of duplication is zero, you better have a Goddammed plan of how you're going to add enough value to be attractive.

That's why, even as I care less about free software, I do continue to admire Redhat. They started their business with a plan. And when the market changed and the plan faltered, they got to work on a new plan. This happened to them at least twice, until now Redhat is basically a large consulting firm - which is where most free software VARs seem to end up. But hey, as long as they're making money at it, there's nothing wrong with that.

Sun, on the other hand, seemed to get sucked into the open source zeitgeist of the last decade, rather than deliberately enter it. By 2006 when Schwartz became CEO, the vicious round of consolidations and closures among open source companies was ancient history and he should have been able to learn from it. Instead he seemed to think it was still 1996 and he threw more money at open source products without any clear strategy that I could see. That's why Redhat grew from a dorm room operation to a successful corporation, while Sun dwindled from being a key player to being an easy acquisition.

Friday, May 01, 2009

A Thread Across the Ocean


A Thread Across the Ocean was (to my surprise) the only book I could find that tells the story of laying the first transatlantic communications cable. Luckily, it's a good book. It's a classic story of 19th-century ambition to conquer nature (and get rich doing it) and this book tells it well. Recommendation: acquire.

See also: Cryptonomicon.

Wednesday, April 15, 2009

Putting a background behind a UIView transition


When doing a setAnimationTransition: with a UIView, you can do a "flip left/right" or a "curl up/down". If you do a flip left/right, you'll usually see a blank black screen "behind" the view as it flips. (The built-in Stocks app does this.) Recently someone asked me if you could have something else back there, and I thought "huh, that's interesting, I never tried that" and we investigated. It turns out that you can, but you have to set up the view stack properly.

So let's say we have 3 UIView objects, frontView, backView, and rootView. Before the transition begins, frontView is a visible subview of rootView and backView is not yet in the view stack. You begin an animation block and then (usually) do [frontView removeFromSuperview] followed by [rootView addSubview:backView], then commit the animation block and watch the animation take place. You might think that adding another subview of rootView, one that sits below frontView, would make that view be visible behind the animation during the transition. At least, that's what I thought, but it doesn't work. I'm not sure why, but it seems that rootView and all of his subviews become "invisible" during the transition.

But, but! if you put another UIView under rootView, that view will be visible during the transition. Maybe in your project, your views are already set up that way. But if frontView and backView are immediate subviews of the main window, then of course nothing can be below the main window, and you'll need to interpose another UIView object into your view stack.

Instead of posting sample code, I'm going to suggest downloading the LocateMe sample app from ADC. It's already designed with a "main" view and a "flipside" view who are subviews of a root view, and the root view is a subview of the main window. Get the project, open the MainWindow.xib, and add a UIImageView (for example) in the main window:


Make sure the toggleView method is using UIViewAnimationTransitionFlipFromLeft(Right) in its animation block (it doesn't make sense with the curl up/down animation) and then build and run the project.

Tuesday, January 27, 2009

Rails: Database-less ActiveRecord models


It's not unusual in Rails projects to have one or two model classes that don't inherit from ActiveRecord and don't require an associated table in the database. But what if we want half of that? What if we want a model that does descend from ActiveRecord but doesn't exist in the database? I finally found some code for doing exactly that. Here's an example:


class Feedback < ActiveRecord::Base
  validates_presence_of :mailfrom, :comment

  def self.columns
    @columns ||= []
  end

  def self.column(name, sql_type = nil, default = nil, null = true)
    columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
  end

  column :id
  column :mailfrom
  column :comment
  column :ipaddr
end
I derived this from the code at Caboose's blog. He says he got it from Techoweenie but I can't find it on Technoweenie's site anymore.

So anyway, why would you want this? In Rails, the ActiveRecord class is super powerful. It is of course an ORM first and foremost, but it has other great features. Also, other parts of Rails, ActionView in particular, function at their best if you can provide them with an object descended from ActiveRecord. If you don't have an ActiveRecord object, you have to use form_tag() instead of form_for(), text_field_tag() instead of text_field(), etc. You don't get to use error_messages_for() and you don't get the nifty pre-fills of the model's existing values when you error flash back to the same form.

In my case, I was creating a very simple feedback form so a visitor could provide their email address and leave a comment. The comment would be mailed to the site admins via ActionMailer. I actually had a seperate model, which was descended from ActiveRecord, that made a database record of the time, date, and IP address, but there was no requirement to store the comment itself in the database, so I thought that the Feedback object didn't need to inherit from ActiveRecord. Mistake! Cutting myself off from the best helpers that ActionView offers, something that should have been a dead-simple one-page form became a tedious slog[1] to program. I finally came to my senses and googled around until I found the above code.

I've used ActiveRecord-less models before, so at first I was surprised by my unpleasant experience. Then I thought about it and realized that none of my previous ActiveRecord-less models involved user interaction. They were all "plumbing" and I never needed, or missed, the ActionView helpers. If you're making a view for a model, and that model doesn't inherit from ActiveRecord, you're not doing it The Rails Way.

 [1] "Tedious slog" being relative. I find that Rails raises the bar for ease of (web) programming, to the point where it's actually a shock to deal with the same level of drudgery that PHP inflicts on me on a good day.

Friday, January 23, 2009

EventMachine: a TCP server module for Ruby


I just discovered EventMachine. EM is, at its least, an event-driven library around which you can build a custom TCP server. The nitty-gritty of listening, sending and receiving, and multiplexing connections is all done for you.

That's selling it short, though, because EventMachine can do a lot more. In its own words, EventMachine "provides event-driven I/O using the Reactor pattern." It can be used for other client/server models like serial ports or even interactive keyboard I/O. But it really stands out for abstracting away the low-level hassles of writing a TCP daemon.

Here's a simple Echo service built using EventMachine. (Borrowed from the README file)


require 'rubygems'
require 'eventmachine'

module EchoServer
  def receive_data data
    send_data ">>>you sent: #{data}"
    close_connection if data =~ /quit/i
  end
end

EventMachine::run {
  EventMachine::start_server "192.168.0.100", 8081, EchoServer
}
Here's an example I made. You can pass a class to EventMachine::start_server, and each new connection will create a new instance of your class. That allows you to use instance variables to record distinct state for each connection. This example buffers up the client input until the client sends a ".<CRLF>" a la SMTP, or a maximum of 10 lines.


require 'rubygems'
require 'eventmachine'

class DataBuffer < EM::Protocols::LineAndTextProtocol
  def initialize
    puts "init'ing new instance of #{self.class.to_s}"
    @line_ctr = 0
    @databuf = []
  end

  def receive_data(data)
    @databuf << data
    @line_ctr += 1
    if data == ".\r\n" || @line_ctr == 10
      if data == ".\r\n"
        @databuf.pop
      end
      send_data(@databuf.to_s)
      reset_databuf()
    end
  end

  private
  def reset_databuf
    @line_ctr = 0
    @databuf = []
  end
end

EventMachine::run {
  EventMachine::start_server "127.0.0.1", 8081, DataBuffer
}
And the best part is, I've only been playing with EventMachine for about an hour! I've only begun to understand what it can do.

So, yeah. EventMachine is badass. You should check it out.