[UI] Update for revised schema.

 - This update currently drops the `dependents` view from individual rule
   results, because we can't easily satisfy this query in the denormalized
   schema. We will probably want to build up indices in the loaded database in
   order to be able to answer these queries efficiently.
diff --git a/products/ui/llbuildui/model.py b/products/ui/llbuildui/model.py
index d8862db..3a98b0c 100644
--- a/products/ui/llbuildui/model.py
+++ b/products/ui/llbuildui/model.py
@@ -24,12 +24,12 @@
     id = Column(Integer, nullable=False, primary_key=True)
     key_id = Column(Integer, ForeignKey(KeyName.id),
                      nullable=False)
-    value_bytes = Column("value", Integer, nullable=False)
+    value_bytes = Column("value", Binary, nullable=False)
     built_at = Column(Integer, nullable=False)
     computed_at = Column(Integer, nullable=False)
 
     key = relation(KeyName)
-    dependencies = relationship('RuleDependency')
+    dependencies_bytes = Column("dependencies", Binary, nullable=True)
 
     def __repr__(self):
         return "%s%r" % (
@@ -40,21 +40,15 @@
     def value(self):
         return BuildValue(self.value_bytes)
 
-class RuleDependency(Base):
-    __tablename__ = "rule_dependencies"
-
-    rule_id = Column(Integer, ForeignKey(RuleResult.id),
-                     nullable=False, primary_key=True)
-    key_id = Column(Integer, ForeignKey(KeyName.id),
-                     nullable=False, primary_key=True)
-
-    rule = relation(RuleResult)
-    key = relation(KeyName)
+    @property
+    def dependencies(self):
+        if self.dependencies_bytes is None:
+            return []
+        else :
+            num_dependencies = len(self.dependencies_bytes) / 8
+            return struct.unpack("<" + str(num_dependencies) + "Q",
+                                 self.dependencies_bytes)
     
-    def __repr__(self):
-        return "%s%r" % (
-            self.__class__.__name__, (self.rule_id, self.key))
-
 ###
 
 class BuildValue(object):
@@ -66,7 +60,7 @@
         "Invalid",
         "VirtualInput", "ExistingInput", "MissingInput",
         "DirectoryContents", "DirectoryTreeSignature",
-        "MissingOutput", "FailedInput",
+        "StaleFileRemoval", "MissingOutput", "FailedInput",
         "SuccessfulCommand", "FailedCommand",
         "PropagatedFailureCommand", "CancelledCommand", "SkippedCommand",
         "Target",
@@ -124,7 +118,7 @@
 
     @property
     def hasStringList(self):
-        return self.kind in ("DirectoryContents",)
+        return self.kind in ("DirectoryContents", "StaleFileRemoval")
 
     @property
     def hasOutputInfo(self):
diff --git a/products/ui/llbuildui/templates/db_rule_result.html b/products/ui/llbuildui/templates/db_rule_result.html
index 78aa73f..f1c5943 100644
--- a/products/ui/llbuildui/templates/db_rule_result.html
+++ b/products/ui/llbuildui/templates/db_rule_result.html
@@ -10,6 +10,7 @@
 </a><br>
 {% endfor %}
 
+<!-- FIXME: This view is not currently supported
 <h4>Dependents</h4>
 
 {% for dependent in dependents_results %}
@@ -17,6 +18,7 @@
   {{ dependent.key.name }} (id: {{ dependent.id }})
 </a><br>
 {% endfor %}
+-->
 
 <h4>Value</h4>
 {{ rule_result.value }}
diff --git a/products/ui/llbuildui/views.py b/products/ui/llbuildui/views.py
index 4538268..50ba4b3 100644
--- a/products/ui/llbuildui/views.py
+++ b/products/ui/llbuildui/views.py
@@ -1,5 +1,6 @@
 import flask
 import sqlalchemy.sql
+import sqlalchemy.sql.expression
 
 from flask import Flask, current_app, g, redirect, request, session, url_for
 
@@ -47,13 +48,15 @@
     # Compute the roots of the results.
     #
     # We compute this by simply looking for nodes which have no dependencies.
-    roots_query = s.query(model.RuleResult) \
-                  .filter(model.RuleResult.key_id.notin_(
-                      s.query(model.RuleDependency.key_id)))
+    dependees = set()
+    for result in s.query(model.RuleResult):
+        for item in result.dependencies:
+            dependees.add(item)
+    roots = [result
+             for result in s.query(model.RuleResult)
+             if result.key_id not in dependees]
 
-    return flask.render_template(
-        "db_root.html",
-        db_path=db_path, roots=roots_query.all())
+    return flask.render_template("db_root.html", db_path=db_path, roots=roots)
 
 @main.route('/db/config', methods=['GET', 'POST'])
 def db_config():
@@ -82,7 +85,7 @@
         # Get the dependencies.
         succs = []
         for dependency in rule.dependencies:
-            succs.append(dependency.key_id)
+            succs.append(dependency)
         return succs
     keys = sorted(rules.keys())
     cycle = graphalgorithms.find_cycle(keys, successors)
@@ -106,17 +109,12 @@
         model.KeyName.name == name).one()
     dependency_results = [
         s.query(model.RuleResult).filter_by(
-            key=dependency.key).one()
+            key_id=dependency).one()
         for dependency in rule_result.dependencies]
-    dependents_results = s.query(model.RuleResult) \
-                          .filter(model.RuleResult.id.in_(
-                              s.query(model.RuleDependency.rule_id).filter_by(
-                                  key=rule_result.key)))
+    # FIXME: We need to get back the dependents view, it was super useful.
     dependency_results = sorted(dependency_results, key=lambda d: d.key.name)
-    dependents_results = sorted(dependents_results, key=lambda d: d.key.name)
     
     return flask.render_template(
         "db_rule_result.html",
         db_path=session.get("db"), rule_result=rule_result,
-        dependency_results=dependency_results,
-        dependents_results=dependents_results)
+        dependency_results=dependency_results)