[thrift] spruce up Erlang binding for tonight's release

Summary:
 * got rid of most of the otp_base jonx ... save that for a future release unfortunately
 * cleaned up the tutorial server, added -erl to tutorial.thrift's shebang
 * made better README and TODO

Test Plan: checked out a copy, read my directions, built and ran the tutorial, and pretended that it didn't blow


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665273 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/erl/src/Makefile b/lib/erl/src/Makefile
new file mode 100644
index 0000000..1a07b0a
--- /dev/null
+++ b/lib/erl/src/Makefile
@@ -0,0 +1,112 @@
+# $Id: Makefile,v 1.3 2004/08/13 16:35:59 mlogan Exp $
+#
+include ../build/otp.mk
+include ../build/colors.mk
+include ../build/buildtargets.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+
+include ../vsn.mk
+APP_NAME=thrift
+PFX=thrift
+VSN=$(THRIFT_VSN)
+
+# ----------------------------------------------------
+# Install directory specification
+# WARNING: INSTALL_DIR the command to install a directory.
+#          INSTALL_DST is the target directory
+# ----------------------------------------------------
+INSTALL_DST = $(ERLANG_OTP)/lib/$(APP_NAME)-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+
+MODULES = $(shell find -name \*.erl | sed s:^\\./:: | sed s/\\.erl//)
+MODULES_STRING_LIST = $(shell find -name \*.erl | sed s:^\\./:\": | sed s/\\.erl/\",/)
+
+HRL_FILES=
+INTERNAL_HRL_FILES= $(APP_NAME).hrl
+ERL_FILES= $(MODULES:%=%.erl)
+DOC_FILES=$(ERL_FILES)
+
+APP_FILE= $(APP_NAME).app
+APPUP_FILE= $(APP_NAME).appup
+
+APP_SRC= $(APP_FILE).src
+APPUP_SRC= $(APPUP_FILE).src
+
+APP_TARGET= $(EBIN)/$(APP_FILE)
+APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
+
+BEAMS= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+TARGET_FILES= $(BEAMS) $(APP_TARGET) $(APPUP_TARGET)
+
+WEB_TARGET=/var/yaws/www/$(APP_NAME)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+ERL_FLAGS +=
+ERL_COMPILE_FLAGS += -I../include -I../../fslib/include -I../../system_status/include 
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+all debug opt: $(EBIN) $(TARGET_FILES) 
+
+#$(EBIN)/rm_logger.beam: $(APP_NAME).hrl
+include ../build/docs.mk
+
+# Note: In the open-source build clean must not destroy the preloaded
+# beam files.
+clean:
+	rm -f $(TARGET_FILES)
+	rm -f core
+	rm -rf $(EBIN)
+	rm -rf *html
+
+$(EBIN):
+	mkdir $(EBIN)
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(APP_TARGET): $(APP_SRC) ../vsn.mk $(BEAMS)
+	sed -e 's;%VSN%;$(VSN);' \
+		-e 's;%PFX%;$(PFX);' \
+		-e 's;%APP_NAME%;$(APP_NAME);' \
+		-e 's;%MODULES%;%MODULES%$(MODULES_STRING_LIST);' \
+		$< > $<".tmp" 
+	sed -e 's/%MODULES%\(.*\),/\1/' \
+		$<".tmp" > $@ 
+	rm $<".tmp"
+
+
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+	sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(WEB_TARGET): ../markup/* 
+	rm -rf $(WEB_TARGET) 
+	mkdir $(WEB_TARGET) 
+	cp -r ../markup/ $(WEB_TARGET)
+	cp -r ../skins/ $(WEB_TARGET)
+
+# ----------------------------------------------------
+# Install Target
+# ---------------------------------------------------- 
+
+install: all $(WEB_TARGET)
+#	$(INSTALL_DIR) $(INSTALL_DST)/src
+#	$(INSTALL_DATA) $(ERL_FILES) $(INSTALL_DST)/src
+#	$(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(INSTALL_DST)/src
+#	$(INSTALL_DIR) $(INSTALL_DST)/include
+#	$(INSTALL_DATA) $(HRL_FILES) $(INSTALL_DST)/include
+#	$(INSTALL_DIR) $(INSTALL_DST)/ebin
+#	$(INSTALL_DATA) $(TARGET_FILES) $(INSTALL_DST)/ebin
diff --git a/lib/erl/src/oop.erl b/lib/erl/src/oop.erl
new file mode 100644
index 0000000..e3685ee
--- /dev/null
+++ b/lib/erl/src/oop.erl
@@ -0,0 +1,184 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(oop).
+
+-export([get/2, set/3, call/2, call/3, inspect/1, start_new/2, is_object/1, class/1]).
+-export([behaviour_info/1]).
+
+-include("thrift.hrl").
+-include("oop.hrl").
+
+%%%
+%%% behavior definition
+%%%
+
+behaviour_info(callbacks) -> 
+    [ 
+      {attr, 4}, 
+      {super, 0} 
+    ];
+behaviour_info(_) -> 
+    undefined.
+
+%%
+
+-define(TRIED, lists:reverse([TryModule|TriedRev])).
+
+%% no super attr defined
+-define(NOSUPEROBJ, exit({missing_attr_super, {inspect(Obj), ?TRIED}})).
+
+-define(NOMETHOD, exit({missing_method, {Method, inspect(Obj), tl(Args), ?TRIED}})).
+
+-define(NOATTR, exit({missing_attr, {hd(tl(Args)), inspect(FirstObj), ?TRIED}})).
+
+-define(NOATTR_SET, exit({missing_attr, {Field, inspect(Obj), ".." %% TODO: give a backtrace
+			}})).
+
+
+%%% get(Obj, Field) -> term()
+%%% looks up Field in Obj or its ancestor objects
+
+get(Obj, Field) ->
+    call(Obj, attr, [get, Field, get]).
+
+set(Obj, Field, Value) -> %% TODO: could be tail-recursive
+    Module = ?CLASS(Obj),
+    try
+	Module:attr(Obj, set, Field, Value)
+    catch
+	error:Kind when Kind == undef; Kind == function_clause ->
+	    case get_superobject(Obj) of
+		{ ok, Superobj } ->
+		    Super1 = set(Superobj, Field, Value),
+		    try
+			Module:attr(Obj, set, super, Super1)
+		    catch %% TODO(cpiro): remove check
+			X -> exit({burnsauce, X})
+		    end;
+		none ->
+		    ?NOATTR_SET
+	    end
+    end.
+    
+
+%%% C++                   <-> Erlang
+%%% classes                   modules
+%%%   class b : public a        a:super() -> b.
+%%%   
+
+get_superobject(Obj) ->
+    try
+	{ok, (?CLASS(Obj)):attr(Obj, get, super, get)}
+    catch
+	error:Kind when Kind == undef; Kind == function_clause ->
+	    none
+    end.
+
+is_object(Obj) when is_tuple(Obj) ->
+    try
+	(?CLASS(Obj)):super(), %% if it's an object its first element will be a class name, and it'll have super/0
+	true
+    catch
+	error:Kind when Kind == undef; Kind == function_clause ->
+	    false
+    end;
+is_object(_) ->
+    false.
+
+call(Obj, Method, ArgsProper) ->
+    %% error_logger:info_msg("call called: Obj=~p Method=~p ArgsProper=~p", [inspect(Obj), Method, ArgsProper]),
+    Args = [Obj|ArgsProper], %% prepend This to args
+    TryModule = ?CLASS(Obj),
+    call_loop(Obj, Method, Args, TryModule, [], Obj).
+
+call(Obj, Method) -> 
+    call(Obj, Method, []).
+
+call_loop(Obj, Method, Args, TryModule, TriedRev, FirstObj) ->
+    try
+	%% error_logger:info_msg("call_loop~n ~p~n ~p~n ~p~n ~p", [inspect(Obj), Method, Args, TryModule]),
+	apply(TryModule, Method, Args)
+    catch
+	error:Kind when Kind == undef; Kind == function_clause ->
+	    case { TryModule:super(), Method } of 
+		{ none, attr } ->
+		    ?NOATTR;
+		
+		{ none, _ } -> 
+		    ?NOMETHOD;
+		
+		{ Superclass, attr } -> 
+		    %% look for attrs in the "super object"
+		    
+		    case get_superobject(Obj) of
+			{ok, Superobj} when (TryModule == ?CLASS(Obj)) -> 
+			    %% replace This with Superobj
+			    NewArgs = [Superobj|tl(Args)], 
+			    call_loop(Superobj, Method, NewArgs, 
+				      Superclass, [TryModule|TriedRev], FirstObj);
+			
+			{ok, _Superobj} -> % failed guard TODO(cpiro): removeme
+			    exit(oh_noes);
+			
+			none    -> ?NOSUPEROBJ
+		    end;
+		
+		{ SuperClass, _ } ->
+		    call_loop(Obj, Method, Args, 
+			      SuperClass, [TryModule|TriedRev], FirstObj)
+	    end
+    end.
+    
+class(Obj) when is_tuple(Obj) ->
+    case is_object(Obj) of
+	true ->
+	    ?CLASS(Obj);
+	false ->
+	    none
+    end;
+class(_) ->
+    none.
+
+%% careful: not robust against records beginning with a class name
+%% (note: we can't just guard with is_record(?CLASS(Obj), Obj) since we
+%% can't/really really shouldn't require all record definitions in this file
+inspect(Obj) ->
+    try
+	case is_object(Obj) of
+	    true ->
+		DeepList = inspect_loop(Obj, "#<"),
+		lists:flatten(DeepList);
+	    false ->
+		thrift_utils:sformat("~p", [Obj])
+	end
+    catch
+	_:E ->
+	    thrift_utils:sformat("INSPECT_ERROR(~p) ~p", [E, Obj])
+
+	    %% TODO(cpiro): bring this back once we're done testing:
+	    %% _:E -> thrift_utils:sformat("~p", [Obj])
+    end.
+
+inspect_loop(Obj, Str) ->
+    Class   = ?CLASS(Obj),
+    Inspect = Class:inspect(Obj),
+    Current = atom_to_list(Class) ++ ": " ++ Inspect,
+
+    case get_superobject(Obj) of
+	{ ok, Superobj } ->
+	    inspect_loop(Superobj, Str ++ Current ++ " | ");
+	none ->
+	    Str ++ Current ++ ">"
+    end.
+
+%% TODO: voids take only ok as return? 
+start_new(none=Resv, _) ->
+    error_logger:format("can't instantiate ~p: class name is a reserved word", [Resv]),
+    error;
+start_new(Class, Args) ->
+    {ok, Pid} = gen_server:start_link(thrift_oop_server, {Class, Args}, []),
+    Pid.
diff --git a/lib/erl/src/protocol/tBinaryProtocol.erl b/lib/erl/src/protocol/tBinaryProtocol.erl
new file mode 100644
index 0000000..b745298
--- /dev/null
+++ b/lib/erl/src/protocol/tBinaryProtocol.erl
@@ -0,0 +1,214 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tBinaryProtocol).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("protocol/tProtocolException.hrl").
+-include("protocol/tBinaryProtocol.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([
+  new/1,
+
+  writeMessageBegin/4,
+  writeFieldBegin/4, writeFieldStop/1,
+  writeMapBegin/4,
+  writeListBegin/3,
+  writeSetBegin/3,
+
+  writeBool/2, writeByte/2, writeI16/2, writeI32/2, 
+  writeI64/2, writeDouble/2, writeString/2, 
+
+  readMessageBegin/1, 
+  readFieldBegin/1, 
+  readMapBegin/1, 
+  readListBegin/1, 
+  readSetBegin/1, 
+
+  readBool/1, readByte/1, readI16/1, readI32/1, 
+  readI64/1, readDouble/1, readString/1
+]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tProtocol.
+
+%%% inspect(This) -> string()
+
+inspect(_This) ->
+    "".
+
+%%%
+%%% class methods
+%%%
+
+new(Trans) ->
+    Super = (super()):new(Trans),
+    #?MODULE{super=Super}.
+
+%%%
+%%% instance methods
+%%%
+
+writeMessageBegin(This, Name, Type, Seqid) ->
+    ?L1(writeI32, ?VERSION_1 bor Type),
+    ?L1(writeString, Name),
+    ?L1(writeI32, Seqid),
+    ok.
+
+writeFieldBegin(This, _Name, Type, Id) ->
+    ?L1(writeByte, Type),
+    ?L1(writeI16, Id),
+    ok.
+
+writeFieldStop(This) ->
+    ?L1(writeByte, ?tType_STOP),
+    ok.
+
+writeMapBegin(This, Ktype, Vtype, Size) ->
+    ?L1(writeByte, Ktype),
+    ?L1(writeByte, Vtype),
+    ?L1(writeI32, Size),
+    ok.
+
+writeListBegin(This, Etype, Size) ->
+    ?L1(writeByte, Etype),
+    ?L1(writeI32, Size),
+    ok.
+
+writeSetBegin(This, Etype, Size) ->
+    ?L1(writeByte, Etype),
+    ?L1(writeI32, Size),
+    ok.
+
+%
+
+writeBool(This, Bool) ->
+    case Bool of 
+	true  -> ?L1(writeByte, 1);
+	false -> ?L1(writeByte, 0)
+    end.
+
+writeByte(This, Byte) ->
+    Trans = oop:get(This, trans),
+    ?R1(Trans, write, binary_to_list(<<Byte:8/big>>)).
+
+writeI16(This, I16) ->
+    Trans = oop:get(This, trans),
+    ?R1(Trans, write, binary_to_list(<<I16:16/big>>)).
+
+writeI32(This, I32) ->
+    Trans = oop:get(This, trans),
+    ?R1(Trans, write, binary_to_list(<<I32:32/big>>)).
+
+writeI64(This, I64) ->
+    Trans = oop:get(This, trans),
+    ?R1(Trans, write, binary_to_list(<<I64:64/big>>)).
+
+writeDouble(This, Double) ->
+    Trans = oop:get(This, trans),
+    ?R1(Trans, write, binary_to_list(<<Double:64/big>>)).
+
+writeString(This, Str) ->
+    Trans = oop:get(This, trans),
+    ?L1(writeI32, length(Str)),
+    ?R1(Trans, write, Str).
+
+%
+
+readMessageBegin(This) ->
+    Version = ?L0(readI32),
+    if 
+	(Version band ?VERSION_MASK) /= ?VERSION_1 ->
+	    throw(tProtocolException:new(?tProtocolException_BAD_VERSION,
+					 "Missing version identifier"));
+	true -> ok
+    end,
+    Type = Version band 16#000000ff,
+    Name  = ?L0(readString),
+    Seqid = ?L0(readI32),
+    { Name, Type, Seqid }.
+
+readFieldBegin(This) ->
+    Type = ?L0(readByte),
+    case Type of 
+	?tType_STOP ->
+	    { nil, Type, 0 }; % WATCH
+	_ ->
+	    Id = ?L0(readI16),
+	    { nil, Type, Id }
+    end.
+
+readMapBegin(This) ->
+    Ktype = ?L0(readByte),
+    Vtype = ?L0(readByte),
+    Size  = ?L0(readI32),
+    { Ktype, Vtype, Size }.
+
+readListBegin(This) ->
+    Etype = ?L0(readByte),
+    Size  = ?L0(readI32),
+    { Etype, Size }.
+
+readSetBegin(This) ->
+    Etype = ?L0(readByte),
+    Size  = ?L0(readI32),
+    { Etype, Size }.
+
+%
+
+readBool(This) ->
+    Byte = ?L0(readByte),
+    (Byte /= 0).
+
+readByte(This) ->
+    Trans = oop:get(This, trans),
+    <<Val:8/integer-signed-big, _/binary>>  = ?R1(Trans, readAll, 1),
+    Val.
+
+readI16(This) ->
+    Trans = oop:get(This, trans),
+    <<Val:16/integer-signed-big, _/binary>>  = ?R1(Trans, readAll, 2),
+    Val.
+
+readI32(This) ->
+    Trans = oop:get(This, trans),
+    <<Val:32/integer-signed-big, _/binary>>  = ?R1(Trans, readAll, 4),
+    Val.
+
+readI64(This) ->
+    Trans = oop:get(This, trans),
+    <<Val:64/integer-signed-big, _/binary>>  = ?R1(Trans, readAll, 8),
+    Val.
+
+readDouble(This) ->
+    Trans = oop:get(This, trans),
+    <<Val:64/float-signed-big, _/binary>>  = ?R1(Trans, readAll, 8),
+    Val.
+
+readString(This) ->
+    Trans = oop:get(This, trans),
+    Sz    = ?L0(readI32),
+    binary_to_list(?R1(Trans, readAll, Sz)).
diff --git a/lib/erl/src/protocol/tBinaryProtocolFactory.erl b/lib/erl/src/protocol/tBinaryProtocolFactory.erl
new file mode 100644
index 0000000..ff7fa56
--- /dev/null
+++ b/lib/erl/src/protocol/tBinaryProtocolFactory.erl
@@ -0,0 +1,57 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tBinaryProtocolFactory).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("protocol/tBinaryProtocol.hrl").
+-include("protocol/tBinaryProtocolFactory.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0, getProtocol/2]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tProtocolFactory.
+
+%%% inspect(This) -> string()
+
+inspect(_This) ->
+    "".
+
+%%%
+%%% class methods
+%%%
+
+new() ->
+    Super = (super()):new(),
+    #?MODULE{super=Super}.
+
+%%%
+%%% instance methods
+%%%
+
+getProtocol(_This, Trans) ->
+    oop:start_new(tBinaryProtocol, [Trans]).
+
diff --git a/lib/erl/src/protocol/tProtocol.erl b/lib/erl/src/protocol/tProtocol.erl
new file mode 100644
index 0000000..8900c5d
--- /dev/null
+++ b/lib/erl/src/protocol/tProtocol.erl
@@ -0,0 +1,217 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tProtocol).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("protocol/tProtocol.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+%% -export([interface/1]).	  	             %%
+
+-export([
+  new/1,
+  skip/2,
+
+  writeMessageBegin/4, writeMessageEnd/1,
+  writeStructBegin/2, writeStructEnd/1,
+  writeFieldBegin/4, writeFieldEnd/1, writeFieldStop/1,
+  writeMapBegin/4, writeMapEnd/1,
+  writeListBegin/3, writeListEnd/1,
+  writeSetBegin/3, writeSetEnd/1,
+
+  writeBool/2, writeByte/2, writeI16/2, writeI32/2, 
+  writeI64/2, writeDouble/2, writeString/2, 
+
+  readMessageBegin/1, readMessageEnd/1, 
+  readStructBegin/1, readStructEnd/1, 
+  readFieldBegin/1, readFieldEnd/1,
+  readMapBegin/1, readMapEnd/1,
+  readListBegin/1, readListEnd/1,
+  readSetBegin/1, readSetEnd/1,
+
+  readBool/1, readByte/1, readI16/1, readI32/1, 
+  readI64/1, readDouble/1, readString/1
+]).
+
+%%%
+%%% server interface
+%%%
+
+%% %%% modules we can instantiate from the server	       %%
+%% interface(subclasses) -> 				       %%
+%%     [						       %%
+%%      tBinaryProtocol					       %%
+%%     ];						       %%
+%% 							       %%
+%% %%% synchronous calls to pass			       %%
+%% interface(call) -> 					       %%
+%%     [						       %%
+%%      skip,						       %%
+%%      						       %%
+%%      writeMessageBegin, writeMessageEnd,		       %%
+%%      writeStructBegin, writeStructEnd,		       %%
+%%      writeFieldBegin, writeFieldEnd, writeFieldStop,	       %%
+%%      writeMapBegin, writeMapEnd,			       %%
+%%      writeListBegin, writeListEnd,			       %%
+%%      writeSetBegin, writeSetEnd,			       %%
+%%      						       %%
+%%      writeBool, writeByte, writeI16, writeI32, 	       %%
+%%      writeI64, writeDouble, writeString, 		       %%
+%%      						       %%
+%%      readMessageBegin, readMessageEnd, 		       %%
+%%      readStructBegin, readStructEnd, 		       %%
+%%      readFieldBegin, readFieldEnd,			       %%
+%%      readMapBegin, readMapEnd,			       %%
+%%      readListBegin, readListEnd,			       %%
+%%      readSetBegin, readSetEnd,			       %%
+%%      						       %%
+%%      readBool, readByte, readI16, readI32, 		       %%
+%%      readI64, readDouble, readString			       %%
+%%     ];						       %%
+%% 							       %%
+%% %%% asynchronous casts to pass			       %%
+%% interface(cast) ->					       %%
+%%     [].						       %%
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(trans).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    none.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(trans).
+
+%%%
+%%% class methods
+%%%
+
+new(Trans) ->
+    #?MODULE{trans=Trans}.
+
+%%%
+%%% instance methods
+%%%
+
+writeMessageBegin(_This, _Name, _Type, _Seqid) -> ok.
+writeMessageEnd(_This) -> ok.
+writeStructBegin(_This, _Name) -> ok.
+writeStructEnd(_This) -> ok.
+writeFieldBegin(_This, _Name, _Type, _Id) -> ok.
+writeFieldEnd(_This) -> ok.
+writeFieldStop(_This) -> ok.
+writeMapBegin(_This, _Ktype, _Vtype, _Size) -> ok.
+writeMapEnd(_This) -> ok.
+writeListBegin(_This, _Etype, _Size) -> ok.
+writeListEnd(_This) -> ok.
+writeSetBegin(_This, _Etype, _Size) -> ok.
+writeSetEnd(_This) -> ok.
+
+writeBool(_This, _Value) -> ok.
+writeByte(_This, _Value) -> ok.
+writeI16(_This, _Value) -> ok.
+writeI32(_This, _Value) -> ok.
+writeI64(_This, _Value) -> ok.
+writeDouble(_This, _Value) -> ok.
+writeString(_This, _Value) -> ok.
+
+readMessageBegin(_This) -> ok.
+readMessageEnd(_This) -> ok.
+readStructBegin(_This) -> ok.
+readStructEnd(_This) -> ok.
+readFieldBegin(_This) -> ok.
+readFieldEnd(_This) -> ok.
+readMapBegin(_This) -> ok.
+readMapEnd(_This) -> ok.
+readListBegin(_This) -> ok.
+readListEnd(_This) -> ok.
+readSetBegin(_This) -> ok.
+readSetEnd(_This) -> ok.
+
+readBool(_This) -> ok.
+readByte(_This) -> ok.
+readI16(_This) -> ok.
+readI32(_This) -> ok.
+readI64(_This) -> ok.
+readDouble(_This) -> ok.
+readString(_This) -> ok.
+
+skip(This, Type) ->
+    case Type of 
+	?tType_STOP   -> nil; % WATCH
+	?tType_BOOL   -> ?L0(readBool);
+	?tType_BYTE   -> ?L0(readByte);
+	?tType_I16    -> ?L0(readI16);
+	?tType_I32    -> ?L0(readI32);
+	?tType_I64    -> ?L0(readI64);
+	?tType_DOUBLE -> ?L0(readDouble);
+	?tType_STRING -> ?L0(readString);
+
+	?tType_STRUCT -> 
+	    ?L0(readStructBegin),
+	    skip_struct_loop(This),
+
+	    %% cpiro: this isn't here in the original tprotocol.rb, but i think it's a bug
+	    ?L0(readStructEnd);
+
+	?tType_MAP ->
+	    {Ktype, Vtype, Size} = ?L0(readMapBegin),
+	    skip_map_repeat(This, Ktype, Vtype, Size),
+	    ?L0(readMapEnd);
+
+	?tType_SET -> 
+	    {Etype, Size} = ?L0(readSetBegin),
+	    skip_set_repeat(This, Etype, Size),
+	    ?L0(readSetEnd);
+
+	?tType_LIST ->
+	    {Etype, Size} = ?L0(readListBegin),
+	    skip_set_repeat(This, Etype, Size), % [sic] skipping same as for SET
+	    ?L0(readListEnd)
+    end.
+
+skip_struct_loop(This) ->
+    { _Name, Type, _Id } = ?L0(readFieldBegin),
+    if
+	Type == ?tType_STOP ->
+	    ok;
+	
+	true ->
+	    ?L1(skip, Type),
+	    ?L0(readFieldEnd),
+
+	    %% cpiro: this is here in original tprotocol.rb, but i think it's a bug
+	    % ?L0(readStructEnd),
+	    skip_struct_loop(This)
+    end.
+       
+skip_map_repeat(This, Ktype, Vtype, Times) ->
+    ?L1(skip, Ktype),
+    ?L1(skip, Vtype),
+    skip_map_repeat(This, Ktype, Vtype, Times-1).
+
+skip_set_repeat(This, Etype, Times) ->
+    ?L1(skip, Etype),
+    skip_set_repeat(This, Etype, Times-1).
diff --git a/lib/erl/src/protocol/tProtocolException.erl b/lib/erl/src/protocol/tProtocolException.erl
new file mode 100644
index 0000000..d926aff
--- /dev/null
+++ b/lib/erl/src/protocol/tProtocolException.erl
@@ -0,0 +1,58 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tProtocolException).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("protocol/tProtocolException.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0, new/1, new/2]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super);
+?DEFINE_ATTR(type).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tException.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(type).
+
+%%%
+%%% class methods
+%%%
+
+new(Type, Message) ->
+    Super = (super()):new(Message),
+    #?MODULE{super=Super, type=Type}.
+
+new() ->
+    new(?tProtocolException_UNKNOWN, undefined).
+new(Type) ->
+    new(Type, undefined).
+
+%%%
+%%% instance methods
+%%%
diff --git a/lib/erl/src/protocol/tProtocolFactory.erl b/lib/erl/src/protocol/tProtocolFactory.erl
new file mode 100644
index 0000000..d697263
--- /dev/null
+++ b/lib/erl/src/protocol/tProtocolFactory.erl
@@ -0,0 +1,54 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tProtocolFactory).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("protocol/tProtocolFactory.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0, getProtocol/2]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?ATTR_DUMMY.
+
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    none.
+
+%%% inspect(This) -> string()
+
+inspect(_This) ->
+    "".
+
+%%%
+%%% class methods
+%%%
+
+new() ->
+    #?MODULE{}.
+
+%%%
+%%% instance methods
+%%%
+
+getProtocol(This, Trans) ->
+    nil.
diff --git a/lib/erl/src/server/tErlServer.erl b/lib/erl/src/server/tErlServer.erl
new file mode 100644
index 0000000..0e61e38
--- /dev/null
+++ b/lib/erl/src/server/tErlServer.erl
@@ -0,0 +1,117 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tErlServer).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("transport/tTransportException.hrl").
+-include("server/tErlServer.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/6, new/5, new/4, effectful_serve/1, effectful_new_acceptor/1, catches/3]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super);
+?DEFINE_ATTR(acceptor);
+?DEFINE_ATTR(listenSocket);
+?DEFINE_ATTR(port).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tServer.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(acceptor) ++ ", " ++
+    ?FORMAT_ATTR(listenSocket) ++ ", " ++
+    ?FORMAT_ATTR(port).
+
+%%%
+%%% class methods
+%%%
+
+new(Port, Handler, Processor, ServerTransport, TransportFactory, ProtocolFactory) ->
+    Super = (super()):new(Handler, Processor, ServerTransport, TransportFactory, ProtocolFactory),
+    #?MODULE{super=Super, port=Port, listenSocket=nil, acceptor=nil}.
+
+new(Port, Handler, Processor, ServerTransport) ->
+    new(Port, Handler, Processor, ServerTransport, nil, nil).
+
+new(Port, Handler, Processor, ServerTransport, TransportFactory) ->
+    new(Port, Handler, Processor, ServerTransport, TransportFactory, nil).
+
+% listenSocket, acceptor, port
+
+effectful_serve(This) ->
+    Port = oop:get(This, port),
+
+    Options = [binary, {packet, 0}, {active, false}],
+
+    %% listen
+    case gen_tcp:listen(Port, Options) of 
+	{ok, ListenSocket} ->
+	    ?INFO(server_listening, {Port}),
+
+	    This1 = oop:set(This, listenSocket, ListenSocket),
+
+	    %% spawn acceptor
+	    {_Acceptor, This2} = effectful_new_acceptor(This1),
+
+	    {ok, This2};
+
+	{error, eaddrinuse} ->
+	    error_logger:format("couldn't bind port ~p, address in use", [Port]),
+	    {{error, eaddrinuse}, This} %% state before the accept
+    end.
+
+effectful_new_acceptor(This) ->
+    ListenSocket = oop:get(This, listenSocket),
+    Processor    = oop:get(This, processor), %% cpiro: generated processor, not the "actual" processor
+    Handler      = oop:get(This, handler),
+
+    TF = oop:get(This, transportFactory),
+    PF = oop:get(This, protocolFactory),
+
+    tErlAcceptor = oop:get(This, serverTransport), %% cpiro: only supported ServerTransport
+
+    ServerPid = self(),
+    Acceptor  = oop:start_new(tErlAcceptor, [ServerPid, TF, PF]),
+    ?C3(Acceptor, accept, ListenSocket, Processor, Handler),
+
+    This1 = oop:set(This, acceptor, Acceptor),
+
+    {Acceptor, This1}.
+
+catches(_This, _Pid, normal) ->
+    ok.
+
+%% %% The current acceptor has died, wait a little and try again						       %%
+%% handle_info({'EXIT', Pid, _Abnormal}, #state{acceptor=Pid} = State) ->					       %%
+%%     timer:sleep(2000),											       %%
+%%     iserve_socket:start_link(self(), State#state.listen_socket, State#state.port),				       %%
+%%     {noreply,State};												       %%
+
+%% terminate(Reason, State) ->											       %%
+%%     error_logger:info_msg( "Terminating error: ~p~n", [Reason]), % added					       %%
+%%     gen_tcp:close(State#state.listen_socket),								       %%
+%%     ok.													       %%
+%% 														       %%
diff --git a/lib/erl/src/server/tServer.erl b/lib/erl/src/server/tServer.erl
new file mode 100644
index 0000000..23aef22
--- /dev/null
+++ b/lib/erl/src/server/tServer.erl
@@ -0,0 +1,81 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tServer).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("server/tServer.hrl").
+-include("transport/tTransportFactory.hrl").
+-include("protocol/tBinaryProtocolFactory.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/5, new/4, new/3, serve/1]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(handler);
+?DEFINE_ATTR(processor);
+?DEFINE_ATTR(serverTransport);
+?DEFINE_ATTR(transportFactory);
+?DEFINE_ATTR(protocolFactory).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    none.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(handler) ++ ", " ++
+    ?FORMAT_ATTR(processor) ++ ", " ++
+    ?FORMAT_ATTR(serverTransport) ++ ", " ++
+    ?FORMAT_ATTR(transportFactory) ++ ", " ++
+    ?FORMAT_ATTR(protocolFactory).
+
+%%%
+%%% class methods
+%%%
+
+new(Handler, Processor, ServerTransport, TransportFactory, ProtocolFactory) ->
+    #?MODULE{handler=Handler, processor=Processor, serverTransport=ServerTransport,
+
+	     %% much ado about nothing but
+	     %% subclasses pass nil too
+	     transportFactory = 
+	     case TransportFactory of
+		 nil -> tTransportFactory:new();
+		 _   -> TransportFactory
+	     end,
+	     
+	     protocolFactory = 
+	     case ProtocolFactory of
+		 nil -> tBinaryProtocolFactory:new();
+		 _   -> ProtocolFactory
+	     end     
+}.
+
+new(Handler, Processor, ServerTransport) ->
+    new(Handler, Processor, ServerTransport, nil, nil).
+
+new(Handler, Processor, ServerTransport, TransportFactory) ->
+    new(Handler, Processor, ServerTransport, TransportFactory, nil).
+
+serve(_This) ->
+    ok.
diff --git a/lib/erl/src/server/tSimpleServer.erl b/lib/erl/src/server/tSimpleServer.erl
new file mode 100644
index 0000000..6dcc723
--- /dev/null
+++ b/lib/erl/src/server/tSimpleServer.erl
@@ -0,0 +1,111 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+%%% NOTE: tSimpleServer's design isn't compatible with our concurrency model.
+%%% It won't work in principle, and certainly not in practice.  YMMV.
+
+-module(tSimpleServer).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("transport/tTransportException.hrl").
+-include("server/tSimpleServer.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/5, new/4, new/3, serve/1]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tServer.
+
+%%% inspect(This) -> string()
+
+inspect(_This) ->
+    "".
+
+%%%
+%%% class methods
+%%%
+
+new(Handler, Processor, ServerTransport, TransportFactory, ProtocolFactory) ->
+    Super = (super()):new(Handler, Processor, ServerTransport, TransportFactory, ProtocolFactory),
+    error_logger:warning_msg("tSimpleServer has an incompatable design and doesn't work.  Promise."),
+    #?MODULE{super=Super}.
+
+new(Handler, Processor, ServerTransport) ->
+    new(Handler, Processor, ServerTransport, nil, nil).
+
+new(Handler, Processor, ServerTransport, TransportFactory) ->
+    new(Handler, Processor, ServerTransport, TransportFactory, nil).
+
+%
+
+serve(This) ->
+    exit(tSimpleServer_doesnt_work),
+    ST = oop:get(This, serverTransport),
+    ?R0(ST, effectful_listen),
+
+    serve_loop(This).
+
+serve_loop(This) ->
+    error_logger:info_msg("ready.", []),
+
+    ST     = oop:get(This, serverTransport),
+    Client = ?RT0(ST, accept, infinity),
+
+    TF     = oop:get(This, transportFactory),
+    Trans  = ?F1(TF, getTransport, Client), %% cpiro: OPAQUE!! Trans = Client
+
+    PF     = oop:get(This, protocolFactory),
+    Prot   = ?F1(PF, getProtocol, Trans), %% cpiro: OPAQUE!! Prot = start_new(tBinaryProtocol, [Trans])
+
+    error_logger:info_msg("client accept()ed", []),
+
+    serve_loop_loop(This, Prot), % giggle loop?
+
+    ?R0(Trans, effectful_close),
+
+    serve_loop(This).
+    
+serve_loop_loop(This, Prot) ->
+    Next = 
+	try
+	    Handler   = oop:get(This, handler),
+	    Processor = oop:get(This, processor),
+	    Val = apply(Processor, process, [Handler, Prot, Prot]), %% TODO(cpiro): make processor a gen_server instance
+	    error_logger:info_msg("request processed: rv=~p", [Val]),
+	    loop
+	catch 
+	    %% TODO(cpiro) case when is_record(...) to pick out our exception
+	    %% records vs. normal erlang throws
+	    E when is_record(E, tTransportException) ->
+		error_logger:info_msg("tTransportException (normal-ish?)", []),
+		close;
+	    F ->
+		error_logger:info_msg("EXCEPTION: ~p", [F]),
+		close
+	end,
+    case Next of 
+	loop -> serve_loop_loop(This, Prot);
+	close -> ok
+    end.
diff --git a/lib/erl/src/tApplicationException.erl b/lib/erl/src/tApplicationException.erl
new file mode 100644
index 0000000..568b9c9
--- /dev/null
+++ b/lib/erl/src/tApplicationException.erl
@@ -0,0 +1,115 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tApplicationException).
+
+-include("thrift.hrl").
+-include("tApplicationException.hrl").
+
+-include("oop.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0, new/1, new/2, read/2, write/2]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super);
+?DEFINE_ATTR(type).
+   
+%%%
+%%% behavior callbacks
+%%%
+
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tException.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(type).
+
+%%%
+%%% class methods
+%%%
+
+new(Type, Message) ->
+    Super = (super()):new(Message),
+    #?MODULE{super=Super, type=Type}.
+
+new()     -> new(?tApplicationException_UNKNOWN, undefined).
+new(Type) -> new(Type, undefined).
+
+%%%
+%%% instance methods
+%%%
+
+read(This, Iprot) ->
+    ?R0(Iprot, readStructBegin),
+    read_while_loop(This, Iprot),
+    ?R0(Iprot, readStructEnd),
+    ok.
+
+read_while_loop(This, Iprot) ->
+    {_Fname, Ftype, Fid} = ?R0(Iprot, readFieldBegin),
+
+    if 
+	Ftype == ?tType_STOP ->
+	    ok;
+
+	(Fid == 1) and (Ftype == ?tType_STRING) ->
+	    Message1 = ?R0(Iprot, readString),
+	    This1 = oop:set(This, message, Message1),
+	    ?R0(Iprot, readFieldEnd),
+	    read_while_loop(This1, Iprot);
+
+	Fid == 1 ->
+	    ?R0(Iprot, skip),
+	    ?R0(Iprot, readFieldEnd),
+	    read_while_loop(This, Iprot);
+
+	(Fid == 2) and (Ftype == ?tType_I32) ->
+	    Type1 = ?R0(Iprot, readI32),
+	    This1 = oop:set(This, type, Type1),
+	    ?R0(Iprot, readFieldEnd),
+	    read_while_loop(This1, Iprot);
+
+        true -> 
+	    ?R0(Iprot, skip),
+	    ?R0(Iprot, readFieldEnd),
+	    read_while_loop(This, Iprot)
+    end.
+
+write(This, Oprot) ->	
+    ?R1(Oprot, writeStructBegin, "tApplicationException"),
+    Message = oop:get(This, message),
+    Type    = oop:get(This, type),
+
+    if	Message /= undefined ->
+	    ?R3(Oprot, writeFieldBegin, "message", ?tType_STRING, 1),
+	    ?R1(Oprot, writeString, Message),
+	    ?R0(Oprot, writeFieldEnd);
+        true -> ok
+    end,
+
+    if  Type /= undefined -> 
+	    ?R3(Oprot, writeFieldBegin, "type", ?tType_I32, 2),
+	    ?R1(Oprot, writeI32, Type),
+	    ?R0(Oprot, writeFieldEnd);
+        true -> ok
+    end,
+
+    ?R0(Oprot, writeFieldStop),
+    ?R0(Oprot, writeStructEnd),
+    ok.
diff --git a/lib/erl/src/tErlProcessor.erl b/lib/erl/src/tErlProcessor.erl
new file mode 100644
index 0000000..a6d1073
--- /dev/null
+++ b/lib/erl/src/tErlProcessor.erl
@@ -0,0 +1,63 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tErlProcessor).
+
+-include("thrift.hrl").
+-include("oop.hrl").
+-include("tErlProcessor.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/2, process/3]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super);
+?DEFINE_ATTR(generatedProcessor);
+?DEFINE_ATTR(handler).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tProcessor.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(generatedProcessor) ++ ", " ++
+    ?FORMAT_ATTR(handler).
+
+%%%
+%%% class methods
+%%%
+
+new(GP, Handler) ->
+    Super = (super()):new(),
+    #?MODULE{super = Super, generatedProcessor = GP, handler = Handler}.
+
+%% processor is generated code
+%% handler is user code
+
+%%%
+%%% instance methods
+%%%
+
+process(This, Iprot, Oprot) ->
+    GP      = oop:get(This, generatedProcessor),
+    Handler = oop:get(This, handler),
+
+    GP:process(Handler, Iprot, Oprot).
diff --git a/lib/erl/src/tException.erl b/lib/erl/src/tException.erl
new file mode 100644
index 0000000..0ec4c94
--- /dev/null
+++ b/lib/erl/src/tException.erl
@@ -0,0 +1,50 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tException).
+
+-include("oop.hrl").
+-include("tException.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/1]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(message).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    none.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(message).
+
+%%%
+%%% class methods
+%%%
+
+new(Message) ->
+    #?MODULE{message=Message}.
+
+%%%
+%%% instance methods
+%%%
+
diff --git a/lib/erl/src/tProcessor.erl b/lib/erl/src/tProcessor.erl
new file mode 100644
index 0000000..003748a
--- /dev/null
+++ b/lib/erl/src/tProcessor.erl
@@ -0,0 +1,50 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tProcessor).
+
+-include("oop.hrl").
+-include("tProcessor.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?ATTR_DUMMY.
+
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    none.
+
+%%% inspect(This) -> string()
+
+inspect(_This) ->
+    "".
+
+%%%
+%%% class methods
+%%%
+
+new() ->
+    #?MODULE{}.
+
+%%%
+%%% instance methods
+%%%
+
diff --git a/lib/erl/src/thrift.app.src b/lib/erl/src/thrift.app.src
new file mode 100755
index 0000000..dc2926a
--- /dev/null
+++ b/lib/erl/src/thrift.app.src
@@ -0,0 +1,41 @@
+%%% -*- mode:erlang -*-
+{application, %APP_NAME%,
+ [
+  % A quick description of the application.
+  {description, "Thrift bindings"},
+
+  % The version of the applicaton
+  {vsn, "%VSN%"},
+
+  % All modules used by the application. 
+  {modules,
+   [
+	%MODULES%
+   ]},
+
+  % All of the registered names the application uses. This can be ignored.
+  {registered, []},
+
+  % Applications that are to be started prior to this one. This can be ignored
+  % leave it alone unless you understand it well and let the .rel files in 
+  % your release handle this. 
+  {applications,
+   [
+    kernel, 
+    stdlib
+   ]},
+
+  % OTP application loader will load, but not start, included apps. Again
+  % this can be ignored as well.  To load but not start an application it
+  % is easier to include it in the .rel file followed by the atom 'none'
+  {included_applications, []},
+
+  % configuration parameters similar to those in the config file specified
+  % on the command line. can be fetched with gas:get_env
+  {env, []},
+
+  % The Module and Args used to start this application.
+  {mod, {%APP_NAME%, []}}
+ ]
+}.
+
diff --git a/lib/erl/src/thrift.appup.src b/lib/erl/src/thrift.appup.src
new file mode 100755
index 0000000..54a6383
--- /dev/null
+++ b/lib/erl/src/thrift.appup.src
@@ -0,0 +1 @@
+{"%VSN%",[],[]}.
diff --git a/lib/erl/src/thrift.erl b/lib/erl/src/thrift.erl
new file mode 100644
index 0000000..feabb1d
--- /dev/null
+++ b/lib/erl/src/thrift.erl
@@ -0,0 +1,25 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(thrift).
+
+-export([start/2, shutdown/0, stop/1]).
+-behaviour(application).
+
+-include("thrift.hrl").
+
+%%%
+%%% behavior definition
+%%%
+
+start(Type, StartArgs) ->
+    ok.
+
+shutdown() ->
+    application:stop(?MODULE).
+
+stop(_State) ->
+    ok.
diff --git a/lib/erl/src/thrift_logger.erl b/lib/erl/src/thrift_logger.erl
new file mode 100644
index 0000000..12aa059
--- /dev/null
+++ b/lib/erl/src/thrift_logger.erl
@@ -0,0 +1,307 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(thrift_logger).
+
+-behaviour(gen_event).
+
+-include("thrift_logger.hrl").
+
+%% TODO(cpiro): either
+%% make exceptions know whether they need to be displayed
+%% or not exit with tExecptions for non-errors
+%% or "register" tExceptions with the logger (I LIKE!)
+%% ... we shouldn't need to build any specifics in here
+-include("thrift.hrl").
+-include("oop.hrl").
+-include("transport/tTransportException.hrl").
+
+%% gen_event callbacks
+-export([init/1, handle_event/2, handle_call/2, 
+         handle_info/2, terminate/2, code_change/3]).
+
+-export([install/0, install/1]).
+
+%% ensure the regular logger is out and ours is in
+install() ->
+    install([]).
+install(Args) ->
+    %% remove loggers
+    lists:foreach(fun(Logger) ->
+      case Logger of
+        _ -> gen_event:delete_handler(error_logger, Logger, normal)
+      end end,
+      gen_event:which_handlers(error_logger)),
+
+    %% TODO(cpiro): sasl someday?
+    %% gen_event:add_handler(error_logger, sasl_report_file_h, {LogFile, all}),
+    gen_event:add_handler(error_logger, ?MODULE, Args).
+
+%% how to output
+format(Format, Data) ->
+    io:format(Format, Data).
+
+%% convenience
+sformat(Format, Data) ->
+    thrift_utils:sformat(Format, Data).
+
+%%====================================================================
+%% gen_event callbacks
+%%====================================================================
+%%--------------------------------------------------------------------
+%% @spec init(Args) -> {ok, State}.
+%% 
+%% @doc 
+%% Whenever a new event handler is added to an event manager,
+%% this function is called to initialize the event handler.
+%% @end 
+%%--------------------------------------------------------------------
+init([]) ->
+    {ok, #thrift_logger_state{
+       term_width = 110,
+       force_one_line = true,
+       omit = [oop_new], % req_processed
+       gen_server_messages = false,
+       lookup = true
+      }};
+
+init([State]) ->
+    {ok, State}.
+
+%%--------------------------------------------------------------------
+%% @spec  handle_event(Event, State) -> {ok, State} |
+%%                               {swap_handler, Args1, State1, Mod2, Args2} |
+%%                               remove_handler.
+%% 
+%% @doc 
+%% Whenever an event manager receives an event sent using
+%% gen_event:notify/2 or gen_event:sync_notify/2, this function is called for
+%% each installed event handler to handle the event. 
+%% @end 
+%%--------------------------------------------------------------------
+handle_event2(Symbol, Pid, Type, Message, State) -> % Message must be a string
+    {ok, MessageSafe, NL} = regexp:gsub(Message, "[\n]+", " "), % collapse whitespace to one space
+
+    Type1 =
+	case Type of
+	    "" -> "";
+	    _  -> sformat("~p ", [Type])
+	end,
+
+    Banner     = sformat("~s ~p ~s", [Symbol, Pid, Type1]),
+    BannerLen  = length(Banner),
+    {Output, OutputSafe} = 
+	try %% there's no way to see if Message is a string? just try
+	    {sformat("~s", [Message]),
+	     sformat("~s", [MessageSafe])}
+	catch X -> why_doesnt_this_work
+	end,
+
+    Length =
+	case (length(OutputSafe) + BannerLen) < State#thrift_logger_state.term_width of
+	    true  -> short;
+	    false -> long
+	end,
+
+    OneLine =
+	case NL == 0 of
+	    true  -> oneliner;
+	    false -> multiline
+	end,
+
+    case { State#thrift_logger_state.force_one_line, Length, OneLine } of
+	%% one line and short ... print as is
+	{_, short, oneliner} ->
+	    format("~s~s~n", [Banner, OutputSafe]);
+
+	%% too long ... squash to one
+	{true, long, _} ->
+	    O = Banner ++ OutputSafe,
+	    Format = sformat("~~~ps >~n", [State#thrift_logger_state.term_width-2]), % e.g. "~80s >~n"
+	    format(Format, [O]);
+
+	%% short but multiline... collapse to one
+	{true, short, multiline} ->
+	    format("~s~s~n", [Banner, OutputSafe]);
+
+	%% just print it
+	_ ->
+	    format("~s~n~s~n~n", [Banner, Output])
+    end.
+
+%%
+handle_event1({What, _Gleader, {Pid, Format, Data}}, State) when is_list(Format) ->
+    Symbol = case What of
+	error       -> "!!";
+	warning_msg -> "**";
+	info_msg    -> "..";
+	_Else       -> "??"
+    end,
+
+    case Format of
+	"** Generic server ~p terminating \n** Last message in was ~p~n** When Server state == ~p~n** Reason for termination == ~n** ~p~n" ->
+	    %% v- Pid is a pattern match, not a bind
+	    [Pid, LastMessage, Obj, Reason] = Data,
+
+	    %% TODO: move as much logic as possible out of thrift_logger
+	    Ignore =
+		begin
+		    is_tuple(Reason) andalso
+			size(Reason) >= 1 andalso element(1, Reason) == timeout
+		end
+		orelse
+		begin
+		    case thrift_utils:unnest_record(Reason, tTransportException) of
+			error -> false;
+			{ok, TTE} ->
+			    oop:get(TTE, type) == ?tTransportException_NOT_OPEN andalso
+				oop:get(TTE, message) == "in tSocket:read/2: gen_tcp:recv"
+		    end
+		end,
+
+	    case Ignore of
+		true ->
+		    ok;
+		false ->
+		    Format1 = "** gen_server terminating in message ~p~n** State  = ~s~n** Reason = ~s~n",
+		    Message = sformat(Format1, [LastMessage, oop:inspect(Obj), oop:inspect(Reason)]), %% TODO(cpiro): hope Reason is an object?
+		    handle_event2(Symbol, Pid, "", Message, State)
+	    end;
+	_ ->
+	    Message = sformat(Format, Data),
+	    handle_event2(Symbol, Pid, "", Message, State)
+    end,
+    {ok, State};
+
+handle_event1({What, _Gleader, {Pid, Type, Report}}, State) ->
+    Symbol = case What of
+	error_report   -> "!!";
+	warning_report -> "**";
+	info_report    -> "..";
+	_Else          -> "??"
+    end,
+
+    case Type of
+	{thrift_info, TI} ->
+	    %% should we show it?
+	    case not lists:member(TI, State#thrift_logger_state.omit) of
+		true ->
+		    Message = handle_thrift_info(TI, Report, State),
+		    handle_event2(Symbol, Pid, "", Message, State);
+		false ->
+		    ok
+	    end;
+	crash_report ->
+	    %% [Cruft|_] = Report,									      %%
+	    %% {value, {_, Reason}} = lists:keysearch(error_info, 1, Cruft),				      %%
+	    %% {value, {_, {_, _, [_,_,_,_, Obj, []]}}} = lists:keysearch(initial_call, 1, Cruft),	      %%
+	    %% sformat("state == ~s~nreason ==~s", [oop:inspect(Obj), oop:inspect(Reason)]),	      %%
+	    ok;
+	progress ->
+	    ok;
+
+	_ ->
+	    Message = sformat("|| ~s", [oop:inspect(Report)]),
+	    handle_event2(Symbol, Pid, Type, Message, State)
+    end,
+    {ok, State};
+
+handle_event1(_Event, State) ->
+    handle_event2("??", "<?.?.?>", "", _Event, State),
+    {ok, State}.
+
+handle_event(Event, State) ->
+    try
+	handle_event1(Event, State)
+    catch
+	_:E ->
+	    format("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~n error logger error:~n ~p~n Event = ~p~n State = ~p~n ~p~n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~n", 
+		   [E, Event, State, erlang:get_stacktrace()]),
+	    {ok, State}
+    end.
+
+%% thrift info handlers
+handle_thrift_info(oop_new, {Args, Class, Object}, State) ->
+    %% arg Class can't come first! Then it'd look like a Class object
+    L = io_lib:format("~p:new(~s) = ~s", [Class, thrift_utils:unbrack(Args), oop:inspect(Object)]),
+    lists:flatten(L);
+
+handle_thrift_info(server_listening, {Port}, State) ->
+    sformat("server listening on port ~p", [Port]);
+
+handle_thrift_info(req_processed, {Value}, State) ->
+    sformat("request: ~p", [Value]);
+
+handle_thrift_info(conn_accepted, {AddrString}, State) ->
+    sformat("connection accepted from ~s", [AddrString]);
+
+handle_thrift_info(conn_timeout, {AddrString}, State) ->
+    sformat("connection timed out from ~s", [AddrString]);
+
+handle_thrift_info(conn_closed, {AddrString}, State) ->
+    sformat("connection closed from ~s", [AddrString]);
+
+handle_thrift_info(Else, Report, State) ->
+    sformat("~p ~s", [Else, oop:inspect(Report)]).
+
+%%--------------------------------------------------------------------
+%% @spec handle_call(Request, State) -> {ok, Reply, State} |
+%%                                {swap_handler, Reply, Args1, State1, 
+%%                                  Mod2, Args2} |
+%%                                {remove_handler, Reply}.
+%% 
+%% @doc 
+%% Whenever an event manager receives a request sent using
+%% gen_event:call/3,4, this function is called for the specified event 
+%% handler to handle the request.
+%% @end 
+%%--------------------------------------------------------------------
+handle_call(_Request, State) ->
+    Reply = ok,
+    {ok, Reply, State}.
+
+%%--------------------------------------------------------------------
+%% @spec handle_info(Info, State) -> {ok, State} |
+%%                             {swap_handler, Args1, State1, Mod2, Args2} |
+%%                              remove_handler.
+%% 
+%% @doc 
+%% This function is called for each installed event handler when
+%% an event manager receives any other message than an event or a synchronous
+%% request (or a system message).
+%% @end 
+%%--------------------------------------------------------------------
+handle_info(_Info, State) ->
+    {ok, State}.
+
+%%--------------------------------------------------------------------
+%% @spec terminate(Reason, State) -> void().
+%% 
+%% @doc 
+%% Whenever an event handler is deleted from an event manager,
+%% this function is called. It should be the opposite of Module:init/1 and 
+%% do any necessary cleaning up. 
+%% @end 
+%%--------------------------------------------------------------------
+terminate(normal, _State) ->
+    ok;
+terminate(Reason, _State) ->
+    format("*****************~n~n  frick, error logger terminating: ~p~n~n*****************~n~n", [Reason]),
+    ok.
+
+%%--------------------------------------------------------------------
+%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}. 
+%% 
+%% @doc 
+%% Convert process state when code is changed
+%% @end 
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.
+
+%%====================================================================
+%%% Internal functions
+%%====================================================================
diff --git a/lib/erl/src/thrift_oop_server.erl b/lib/erl/src/thrift_oop_server.erl
new file mode 100644
index 0000000..c21c434
--- /dev/null
+++ b/lib/erl/src/thrift_oop_server.erl
@@ -0,0 +1,216 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+%%%-------------------------------------------------------------------
+%%% @doc  
+%%% @end
+%%%-------------------------------------------------------------------
+-module(thrift_oop_server).
+
+-behaviour(gen_server).
+%%--------------------------------------------------------------------
+%% Include files
+%%--------------------------------------------------------------------
+-include("oop.hrl").
+
+-include("thrift.hrl").
+
+%%--------------------------------------------------------------------
+%% External exports
+%%--------------------------------------------------------------------
+-export([
+	 start_link/0,
+	 stop/0
+	 ]).
+
+%%--------------------------------------------------------------------
+%% gen_server callbacks
+%%--------------------------------------------------------------------
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+%%--------------------------------------------------------------------
+%% record definitions
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% macro definitions
+%%--------------------------------------------------------------------
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% External functions
+%%====================================================================
+%%--------------------------------------------------------------------
+%% @doc Starts the server.
+%% @spec start_link() -> {ok, pid()} | {error, Reason}
+%% @end
+%%--------------------------------------------------------------------
+start_link() ->
+    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
+
+%%--------------------------------------------------------------------
+%% @doc Stops the server.
+%% @spec stop() -> ok
+%% @end
+%%--------------------------------------------------------------------
+stop() ->
+    gen_server:cast(?SERVER, stop).
+
+%%====================================================================
+%% Server functions
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% Function: init/1
+%% Description: Initiates the server
+%% Returns: {ok, State}          |
+%%          {ok, State, Timeout} |
+%%          ignore               |
+%%          {stop, Reason}
+%%--------------------------------------------------------------------
+
+init({Class, Args}) ->
+    process_flag(trap_exit, true),
+    try
+	State = apply(Class, new, Args),
+	?INFO(oop_new, {Args, Class, State}),
+	{ok, State}
+    catch
+	E -> {stop, {new_failed, E}}
+    end;
+
+init(_) ->
+    {stop, invalid_params}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_call/3
+%% Description: Handling call messages
+%% Returns: {reply, Reply, State}          |
+%%          {reply, Reply, State, Timeout} |
+%%          {noreply, State}               |
+%%          {noreply, State, Timeout}      |
+%%          {stop, Reason, Reply, State}   | (terminate/2 is called)
+%%          {stop, Reason, State}            (terminate/2 is called)
+%%--------------------------------------------------------------------
+
+handle_call(Request, From, State) ->
+    handle_either(call, Request, From, State).
+
+%%--------------------------------------------------------------------
+%% Function: handle_cast/2
+%% Description: Handling cast messages
+%% Returns: {noreply, State}          |
+%%          {noreply, State, Timeout} |
+%%          {stop, Reason, State}            (terminate/2 is called)
+%%--------------------------------------------------------------------
+
+handle_cast(stop, State) ->
+    {stop, normal, State};
+
+handle_cast({Method, Args}, State) ->
+    handle_either(cast, {Method, Args}, undefined, State).
+
+-define(REPLY(Value, State),
+	case Type of 
+	    call -> {reply, Value, State};
+	    cast -> {noreply, State} 
+	end
+). 
+
+handle_either(Type, Request, From, State) ->
+    %% error_logger:info_msg("~p: ~p", [?SERVER, oop:inspect(State)]),
+    %% error_logger:info_msg("handle_call(Request=~p, From=~p, State)", [Request, From]),
+
+    case Request of 
+	{get, [Field]} ->
+	    Value = oop:get(State, Field),
+	    ?REPLY(Value, State);
+
+	{set, [Field, Value]} ->
+	    State1 = oop:set(State, Field, Value),
+	    ?REPLY(Value, State1);
+
+	{class, []} ->
+	    ?REPLY(?CLASS(State), State);
+
+	{Method, Args} ->
+	    handle_method(Type, State, Method, Args);
+
+	_ ->
+	    error_logger:format("no match for Request = ~p", [Request]),
+	    %% {stop, server_error, State} 
+	    {reply, server_error, State}
+    end.
+
+handle_method(Type, State, Method, Args) ->
+    %% is an effectful call?
+    Is_effectful = lists:prefix("effectful_", atom_to_list(Method)),
+    Call         = oop:call(State, Method, Args),
+    
+    %% TODO(cpiro): maybe add error handling here? = catch oop:call?
+    
+    case {Is_effectful, Call} of 
+	{true, {Retval, State1}} ->
+	    ?REPLY(Retval, State1);
+	
+	{true, _MalformedReturn} ->
+	    %% TODO(cpiro): bad match -- remove when we're done converting
+	    error_logger:format("oop:call(effectful_*,..,..) malformed return value ~p", 
+				[_MalformedReturn]),
+	    %% {stop, server_error, State} 
+	    {noreply, State};
+	
+	{false, Retval} ->
+	    ?REPLY(Retval, State)
+    end.
+
+%%--------------------------------------------------------------------
+%% Function: handle_info/2
+%% Description: Handling all non call/cast messages
+%% Returns: {noreply, State}          |
+%%          {noreply, State, Timeout} |
+%%          {stop, Reason, State}            (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_info({'EXIT', Pid, Except} = All, State) ->
+    Result = try
+	oop:call(State, catches, [Pid, Except])
+    catch
+	exit:{missing_method, _} ->
+	    unhandled
+    end,
+
+    case Result of
+	unhandled ->
+	    error_logger:format("unhandled exit ~p", [All]),
+	    {stop, All, State};
+	_WasHandled ->
+	    {noreply, State}
+    end;
+
+handle_info(Info, State) ->
+    error_logger:info_msg("~p", [Info]),
+    {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: terminate/2
+%% Description: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(Reason, State) ->
+    %%error_logger:format("~p terminated!: ~p", [self(), Reason]),
+    ok.
+
+%%--------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+ %%--------------------------------------------------------------------
+code_change(OldVsn, State, Extra) ->
+    {ok, State}.
+
+%%====================================================================
+%%% Internal functions
+%%====================================================================
diff --git a/lib/erl/src/thrift_utils.erl b/lib/erl/src/thrift_utils.erl
new file mode 100644
index 0000000..f78767c
--- /dev/null
+++ b/lib/erl/src/thrift_utils.erl
@@ -0,0 +1,52 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(thrift_utils).
+
+-include("transport/tTransportException.hrl").
+
+-export([tabulate/2, dict_size/1, sformat/2, unbrack/1, first_item/1, unnest_record/2]).
+
+%% tabulate
+tabulate(N,F) ->
+    tabulate(0, N, F).
+
+tabulate(N,M,_) when N==M ->
+    [];
+tabulate(N,M,F) ->
+    [F(N) | tabulate(N+1, M, F)].
+
+%% makin me sad
+dict_size(Dict) ->
+  dict:fold(fun (_,_,I) -> I+1 end,0,Dict).
+
+%% I CAN HAS EAZIER KTHX
+sformat(Format, Data) when is_list(Data) ->
+    lists:flatten(io_lib:format(Format, Data));
+sformat(Format, Item) ->
+    error_logger:warning_msg("sformat called with non-list Data: (~p, ~p)", [Format, Item]),
+    sformat(Format, [Item]).
+
+%% render a list and pick off the square brackets
+unbrack(List) ->
+    List1 = sformat("~w", [List]),
+    string:substr(List1, 2, length(List1)-2).
+
+first_item(DeepTuple) ->
+    case is_tuple(DeepTuple) of
+	true  -> first_item(element(1, DeepTuple));
+	false -> DeepTuple
+    end.
+
+unnest_record(Term, RecordTag) ->
+    case is_record(Term, RecordTag) of
+	true ->
+	    {ok, Term};
+	false when is_tuple(Term) ->
+	    unnest_record(element(1, Term), RecordTag);
+	_ ->
+	    error
+    end.
diff --git a/lib/erl/src/transport/tBufferedTransport.erl b/lib/erl/src/transport/tBufferedTransport.erl
new file mode 100644
index 0000000..48d9fba
--- /dev/null
+++ b/lib/erl/src/transport/tBufferedTransport.erl
@@ -0,0 +1,84 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tBufferedTransport).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("transport/tBufferedTransport.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/1, isOpen/1, open/1, close/1, read/2, effectful_write/2, effectful_flush/1]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super);
+?DEFINE_ATTR(transport);
+?DEFINE_ATTR(wbuf).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tTransport.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(transport) ++
+    ?FORMAT_ATTR(wbuf).
+
+%%%
+%%% class methods
+%%%
+
+new(Transport) ->
+    Super = (super()):new(),
+    #?MODULE{super=Super, transport=Transport, wbuf=""}.
+
+%%%
+%%% instance methods
+%%%
+
+isOpen(This) ->
+    Transport = oop:get(This, transport),
+    ?R0(Transport, isOpen).
+
+open(This) ->
+    Transport = oop:get(This, transport),
+    ?R0(Transport, open).
+
+close(This) ->
+    Transport = oop:get(This, transport),
+    ?R0(Transport, close).
+
+read(This, Sz) ->
+    Transport = oop:get(This, transport),
+    ?R1(Transport, read, Sz).
+
+effectful_write(This, Buf) -> % be sure to rebind This to the retval
+    Wbuf = oop:get(This, wbuf),
+    This1 = oop:set(This, wbuf, Wbuf++Buf), % TODO: ++ efficiency?
+    {ok, This1}.
+
+effectful_flush(This) ->
+    Wbuf = oop:get(This, wbuf),
+    Transport = oop:get(This, transport),    
+    ?R1(Transport, effectful_write, Wbuf),
+    ?R0(Transport, effectful_flush),
+    This1 = oop:set(This, wbuf, ""),
+    {ok, This1}.
diff --git a/lib/erl/src/transport/tBufferedTransportFactory.erl b/lib/erl/src/transport/tBufferedTransportFactory.erl
new file mode 100644
index 0000000..9746aba
--- /dev/null
+++ b/lib/erl/src/transport/tBufferedTransportFactory.erl
@@ -0,0 +1,54 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tBufferedTransportFactory).
+
+-include("oop.hrl").
+-include("transport/tBufferedTransport.hrl").
+-include("transport/tBufferedTransportFactory.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0, getTransport/2]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?ATTR_DUMMY.
+
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tTransportFactory.
+
+%%% inspect(This) -> string()
+
+inspect(_This) ->
+    "".
+
+%%%
+%%% class methods
+%%%
+
+new() ->
+    Super = (super()):new(),
+    #?MODULE{super=Super}.
+
+%%%
+%%% instance methods
+%%%
+
+getTransport(_This, Trans) ->
+    gen_server:start_link(tBufferedTransport, {new, [Trans]}).
diff --git a/lib/erl/src/transport/tErlAcceptor.erl b/lib/erl/src/transport/tErlAcceptor.erl
new file mode 100644
index 0000000..f3308cf
--- /dev/null
+++ b/lib/erl/src/transport/tErlAcceptor.erl
@@ -0,0 +1,153 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tErlAcceptor).
+
+-include("oop.hrl").
+-include("thrift.hrl").
+-include("tApplicationException.hrl").
+-include("transport/tTransportException.hrl").
+-include("transport/tServerSocket.hrl").
+-include("transport/tErlAcceptor.hrl").
+
+-include_lib("kernel/include/inet.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/3, accept/4]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super);
+?DEFINE_ATTR(serverPid);
+?DEFINE_ATTR(transportFactory);
+?DEFINE_ATTR(protocolFactory).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tServerTransport.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(serverPid) ++ ", " ++
+    ?FORMAT_ATTR(transportFactory) ++ ", " ++
+    ?FORMAT_ATTR(protocolFactory).
+
+%%%
+%%% class methods
+%%%
+
+new(ServerPid, TF, PF) ->
+    Super = (super()):new(),
+    #?MODULE{super = Super, 
+	     serverPid = ServerPid,
+	     transportFactory = TF,
+	     protocolFactory = PF
+	    }.
+
+%%%
+%%% instance methods
+%%%
+
+accept(This, ListenSocket, GP, Handler) ->
+    ServerPid = oop:get(This, serverPid),
+
+    case catch gen_tcp:accept(ListenSocket) of
+	{ok, Socket} ->
+	    ?C0(ServerPid, effectful_new_acceptor), %% cast to create new acceptor
+
+	    AddrString = render_addr(Socket),
+	    ?INFO(conn_accepted, {AddrString}),
+
+	    %% start_new(tSocket, [])
+	    Client = oop:start_new(tSocket, []),
+	    ?R1(Client, effectful_setHandle, Socket), %% TODO(cpiro): should we just let this be a param to the constructor?
+
+	    %% cpiro: OPAQUE!! Trans = Client
+	    TF      = oop:get(This, transportFactory),
+	    Trans   = ?F1(TF, getTransport, Client), 
+
+	    %% cpiro: OPAQUE!! Prot = start_new(tBinaryProtocol, [Trans])
+	    PF      = oop:get(This, protocolFactory),
+	    Prot    = ?F1(PF, getProtocol, Trans), 
+
+	    %% start_new(, ...)
+	    Processor = oop:start_new(tErlProcessor, [GP, Handler]), %% TODO
+
+	    case receive_loop(This, Processor, Prot, Prot) of
+		conn_timeout ->
+		    ?INFO(conn_timeout, {AddrString});
+		conn_closed ->
+		    ?INFO(conn_closed, {AddrString});
+		{Class, Else} ->
+		    ?ERROR("unhandled ~p in tErlAcceptor: ~p", [Class, Else])
+	    end,
+	    exit(normal);
+
+	Else ->
+	    R = thrift_utils:sformat("accept() failed: ~p", [Else]),
+	    exit(tTransportException:new(R))
+    end.
+
+receive_loop(This, Processor, Iprot, Oprot) ->
+    try ?R2(Processor, process, Iprot, Oprot) of
+	{error, TAE} when is_record(TAE, tApplicationException),
+	                  TAE#tApplicationException.type == ?tApplicationException_HANDLER_ERROR ->
+	    ?ERROR("handler returned an error: ~p", [oop:get(TAE, message)]),
+	    receive_loop(This, Processor, Iprot, Oprot);
+	Value ->
+	    ?INFO(req_processed, {Value}),
+	    receive_loop(This, Processor, Iprot, Oprot)
+    catch
+	exit:{timeout, _} ->
+	    conn_timeout;
+
+	%% the following clause must be last
+	%% cpiro: would be best to implement an is_a/2 guard BIF
+	%% cpiro: breaks if it's a subclass of tTransportException
+	%% since unnest_record knows nothing about oop
+	Class:Else ->
+	    case thrift_utils:unnest_record(Else, tTransportException) of
+		{ok, TTE} when TTE#tTransportException.type == ?tTransportException_NOT_OPEN ->
+		    conn_closed;
+		_ ->
+		    {Class, Else}
+	    end
+    end.
+
+%% helper functions
+
+%% @param Socket the socket in question
+%% TODO(cpiro): there probably needs to be a switch for DoLookup somewhere prominent and outside the lib,
+%% probably at the "application" level
+render_addr(Socket) ->
+    DoLookup = true,
+    {ok, {Peer, Port}} = inet:peername(Socket),
+
+    case Peer of
+	_ when DoLookup ->
+	    case catch inet:gethostbyaddr(Peer) of
+		{ok, Hostent} ->
+		    thrift_utils:sformat("~s:~p", [Hostent#hostent.h_name, Port]);
+		_ ->
+		    "??"
+	    end;
+
+	{A,B,C,D} when not DoLookup ->
+	    thrift_utils:sformat("~p.~p.~p.~p:~p", [A,B,C,D,Port])
+    end.
diff --git a/lib/erl/src/transport/tServerSocket.erl b/lib/erl/src/transport/tServerSocket.erl
new file mode 100644
index 0000000..d0cbf92
--- /dev/null
+++ b/lib/erl/src/transport/tServerSocket.erl
@@ -0,0 +1,96 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tServerSocket).
+
+-include("oop.hrl").
+-include("thrift.hrl").
+-include("transport/tServerSocket.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/1, effectful_listen/1, accept/1, effectful_close/1]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super);
+?DEFINE_ATTR(port);
+?DEFINE_ATTR(handle).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tServerTransport.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(port) ++ ", " ++
+    ?FORMAT_ATTR(handle).
+
+%%%
+%%% class methods
+%%%
+
+new(Port) ->
+    Super = (super()):new(),
+    #?MODULE{super = Super, port = Port, handle = nil}.
+
+%%%
+%%% instance methods
+%%%
+
+effectful_listen(This) ->
+    Port = oop:get(This, port),
+    Options = [binary, {packet, 0}, {active, false}], % was []
+
+    case gen_tcp:listen(Port, Options) of 
+	{ok, ListenSocket} ->
+	    This1 = oop:set(This, handle, ListenSocket),
+	    {ok, This1}
+    
+	% {error, _} -> 
+	% TODO: no error handling in Ruby version?
+    end.
+
+accept(This) ->
+    case oop:get(This, handle) of 
+	nil ->
+	    nil; % cpiro: sic the Ruby code
+
+	Handle ->
+	    case gen_tcp:accept(Handle) of
+		{ok, Sock} ->
+		    Trans = oop:start_new(tSocket, []),
+		    ?R1(Trans, effectful_setHandle, Sock),
+		    Trans
+	        % {error, _} -> 
+                % TODO: no error handling in Ruby version?
+	    end
+    end.
+
+effectful_close(This) ->
+    case oop:get(This, handle) of 
+	nil ->
+	    {nil, This};
+	Handle ->
+	    case gen_tcp:close(Handle) of 
+		ok ->
+		    {ok, This} % cpiro: sic the Ruby version: don't set handle to nil
+	        % {error, _} -> 
+                % TODO: no error handling in Ruby version?
+	    end
+    end.
diff --git a/lib/erl/src/transport/tServerTransport.erl b/lib/erl/src/transport/tServerTransport.erl
new file mode 100644
index 0000000..dfc9ccb
--- /dev/null
+++ b/lib/erl/src/transport/tServerTransport.erl
@@ -0,0 +1,52 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tServerTransport).
+
+-include("oop.hrl").
+-include("transport/tServerTransport.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?ATTR_DUMMY.
+
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    none.
+
+%%% inspect(This) -> string()
+
+inspect(_This) ->
+    "".
+
+%%%
+%%% class methods
+%%%
+
+new() ->
+    #?MODULE{}.
+
+%%%
+%%% instance methods
+%%%
+
+getTransport(_This, Trans) ->
+    Trans.
diff --git a/lib/erl/src/transport/tSocket.erl b/lib/erl/src/transport/tSocket.erl
new file mode 100644
index 0000000..491d86b
--- /dev/null
+++ b/lib/erl/src/transport/tSocket.erl
@@ -0,0 +1,123 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tSocket).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("transport/tTransportException.hrl").
+% -include("transport/tTransport.hrl").
+-include("transport/tSocket.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0, new/1, new/2, 
+	 effectful_setHandle/2, effectful_open/1, 
+	 isOpen/1, write/2, read/2, effectful_close/1]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super);
+?DEFINE_ATTR(host);
+?DEFINE_ATTR(port);
+?DEFINE_ATTR(handle).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tTransport.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(host) ++ ", " ++
+    ?FORMAT_ATTR(port) ++ ", " ++
+    ?FORMAT_ATTR(handle).
+
+%%%
+%%% class methods
+%%%
+
+new(Host, Port) ->
+    Super = (super()):new(),
+    #?MODULE{super=Super, host=Host, port=Port, handle=nil}.
+
+new(Host) ->
+    new(Host, 9090).
+
+new() ->
+    new("localhost", 9090).
+    
+%%%
+%%% instance methods
+%%%
+
+effectful_setHandle(This, Handle) ->
+    {ok, oop:set(This, handle, Handle)}.
+
+effectful_open(This) -> 
+    Host = oop:get(This, host),
+    Port = oop:get(This, port),
+    Options = [],
+
+    case gen_tcp:connect(Host, Port, Options) of
+	{error, _} ->
+	    exit(tTransportException:new(
+		   ?tTransportException_NOT_OPEN,
+		   "Could not connect to " ++ Host ++ ":" ++ Port)
+		 );
+	{ok, Socket} ->
+	    {ok, oop:set(This, handle, Socket)}
+    end.
+
+isOpen(This) ->
+    oop:get(This, handle) /= nil.
+
+write(This, Str) ->
+    Handle = oop:get(This, handle),
+    Val = gen_tcp:send(Handle, Str),
+
+    %% error_logger:info_msg("WRITE |~p| (~p)", [Str,Val]),
+    
+    case Val of
+	{error, _} ->
+	    throw(tTransportException:new(?tTransportException_NOT_OPEN, "in write"));
+	ok ->
+	    ok
+    end.
+
+read(This, Sz) ->
+    Handle = oop:get(This, handle),
+    case gen_tcp:recv(Handle, Sz) of
+	{ok, []} ->
+	    Host = oop:get(This, host),
+	    Port = oop:get(This, port),
+	    throw(tTransportException:new(?tTransportException_UNKNOWN, "TSocket: Could not read " ++ Sz ++ "bytes from " ++ Host ++ ":" ++ Port));
+	{ok, Data} ->
+	    Data;
+	{error, Error} ->
+	    exit(tTransportException:new(?tTransportException_NOT_OPEN, "in tSocket:read/2: gen_tcp:recv"))
+	end.
+	    
+effectful_close(This) ->
+    case oop:get(This, handle) of
+	nil ->
+	    {ok, This};
+	Handle -> 
+	    gen_tcp:close(Handle),
+	    {ok, oop:set(This, handle, nil)}
+    end.
diff --git a/lib/erl/src/transport/tTransport.erl b/lib/erl/src/transport/tTransport.erl
new file mode 100644
index 0000000..6ec115a
--- /dev/null
+++ b/lib/erl/src/transport/tTransport.erl
@@ -0,0 +1,86 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tTransport).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("transport/tTransport.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0, isOpen/1, open/1, close/1, read/2, readAll/2, effectful_write/2, effectful_flush/1]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?ATTR_DUMMY.
+
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    none.
+
+%%% inspect(This) -> string()
+
+inspect(_This) ->
+    "".
+
+%%%
+%%% class methods
+%%%
+
+new() ->
+    #?MODULE{}.
+
+%%%
+%%% instance methods
+%%%
+
+
+
+isOpen(_This) -> nil.
+open(_This) -> nil.
+close(_This) -> nil.
+read(_This, _Sz) -> nil.
+
+readAll(This, Sz) ->
+    readAll_loop(This, Sz, "", 0).
+
+readAll_loop(This, Sz, Buff, Have) ->
+    if 
+	Have < Sz ->
+	    Chunk = ?L1(read, Sz - Have),
+
+	    %% man gen_tcp:
+	    %% exactly Length bytes are returned, or an error; 
+	    %% possibly discarding less than Length bytes of data when 
+	    %% the socket gets closed from the other side.
+
+	    %% error_logger:info_msg("READ |~p|", [Chunk]),
+
+	    Have1 = Have + (Sz-Have), % length(Chunk)
+	    Buff1 = Buff ++ Chunk, % TODO: ++ efficiency?
+	    readAll_loop(This, Sz, Buff1, Have1);
+	true ->
+	    Buff
+    end.
+
+effectful_write(This, _Buf) ->
+    {nil, This}.
+
+effectful_flush(This) ->
+    {nil, This}.
diff --git a/lib/erl/src/transport/tTransportException.erl b/lib/erl/src/transport/tTransportException.erl
new file mode 100644
index 0000000..43a7afa
--- /dev/null
+++ b/lib/erl/src/transport/tTransportException.erl
@@ -0,0 +1,58 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tTransportException).
+
+-include("oop.hrl").
+
+-include("thrift.hrl").
+-include("transport/tTransportException.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0, new/1, new/2]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?DEFINE_ATTR(super);
+?DEFINE_ATTR(type).
+   
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    tException.
+
+%%% inspect(This) -> string()
+
+inspect(This) ->
+    ?FORMAT_ATTR(type).
+
+%%%
+%%% class methods
+%%%
+
+new(Type, Message) ->
+    Super = (super()):new(Message),
+    #?MODULE{super=Super, type=Type}.
+
+new() ->
+    new(?tTransportException_UNKNOWN, undefined).
+new(Type) ->
+    new(Type, undefined).
+
+%%%
+%%% instance methods
+%%%
diff --git a/lib/erl/src/transport/tTransportFactory.erl b/lib/erl/src/transport/tTransportFactory.erl
new file mode 100644
index 0000000..1c8ca61
--- /dev/null
+++ b/lib/erl/src/transport/tTransportFactory.erl
@@ -0,0 +1,52 @@
+%%% Copyright (c) 2007- Facebook
+%%% Distributed under the Thrift Software License
+%%% 
+%%% See accompanying file LICENSE or visit the Thrift site at:
+%%% http://developers.facebook.com/thrift/
+
+-module(tTransportFactory).
+
+-include("oop.hrl").
+-include("transport/tTransportFactory.hrl").
+
+-behavior(oop).
+
+-export([attr/4, super/0, inspect/1]).
+
+-export([new/0, getTransport/2]).
+
+%%%
+%%% define attributes
+%%% 'super' is required unless ?MODULE is a base class
+%%%
+
+?ATTR_DUMMY.
+
+%%%
+%%% behavior callbacks
+%%%
+ 
+%%% super() -> SuperModule = atom()
+%%%             |  none
+
+super() ->
+    none.
+
+%%% inspect(This) -> string()
+
+inspect(_This) ->
+    "".
+
+%%%
+%%% class methods
+%%%
+
+new() ->
+    #?MODULE{}.
+
+%%%
+%%% instance methods
+%%%
+
+getTransport(_This, Trans) ->
+    Trans.