anchor.diff:        return;
       }
       if (message['type'] == "tables") {
  +      List<TableView> tables = new List();
         print ("Received tables message, parsing");
         for (var table in message['tables']) {
  -        var view = new TableView.from_json(table);
  -        print ("$view");
  +        tables.add(new TableView.from_json(table));
         }
  -
  +      _publish("tables", tables);
  +    } else if (message['type'] == "valid_login") {
  +      _publish("valid_login", message['name']);
       } else if (message['type'] != null) {
         var type = message['type'];
         print("Received message with type $type");
         print("Message: $message");
         // TODO: handle
       }
  +  }
  +
  +  _publish(String messageType, dynamic data) {
  +    for (var callback in eventMap[messageType]) {
  +      callback(data);
  +    }
  +  }
  +
  +  subscribe(String messageType, MessageCallback callback) {
  +    // TODO: if types are predefined then create the map structure once
  +    if (!eventMap.containsKey(messageType)) {
  +      eventMap[messageType] = new List();
  +    }
  +    eventMap[messageType].add(callback);
     }
   }
   
  
positive.code:   bool loggedin = false;
    String loginName = "Nobody";
  
    Tarabish();
  
    // Lazy start socket on first login
    _setup_socket() {
      if (_tsocket == null) {
        _tsocket = new TarabishSocket("ws://localhost:42745/websocket");
      }
    }
  
  
negative.code: import 'dart:json' as json;
  import 'package:web_ui/web_ui.dart';
  
  typedef void MessageCallback(dynamic data);
  
  class TarabishSocket {
    // TODO: add logged_in
  