iD.Graph = function(entities) {
    if (!(this instanceof iD.Graph)) return new iD.Graph(entities);

    if (_.isArray(entities)) {
        this.entities = {};
        for (var i = 0; i < entities.length; i++) {
            this.entities[entities[i].id] = entities[i];
        }
    } else {
        this.entities = entities || {};
    }

    this.transients = {};

    if (iD.debug) {
        Object.freeze(this);
        Object.freeze(this.entities);
    }
};

iD.Graph.prototype = {
    entity: function(id) {
        return this.entities[id];
    },

    transient: function(entity, key, fn) {
        var id = entity.id,
            transients = this.transients[id] ||
            (this.transients[id] = {});

        if (transients[key]) {
            return transients[key];
        }

        return transients[key] = fn.call(entity);
    },

    parentWays: function(entity) {
        var graph = this,
            ent,
            node;

        if (!graph.calculatedParentWays) {
            for (var i in graph.entities) {
                ent = graph.entities[i];
                if (ent && ent.type === 'way') {
                    for (var j = 0; j < ent.nodes.length; j++) {
                        node = graph.entities[ent.nodes[j]];
                        node.parentways = node.parentways || [];
                        if (node.parentways.indexOf(ent) < 0) {
                            node.parentways.push(ent);
                        }
                    }
                }
            }
            graph.calculatedParentWays = true;
        }

        return entity.parentways || [];
    },

    parentRelations: function(entity) {
        var graph = this;
        return this.transient(entity, 'parentRelations',
            function generateParentRelations() {
            var o = [], id = this.id;
            for (var i in graph.entities) {
                if (graph.entities[i] &&
                    graph.entities[i].type === 'relation' &&
                    _.find(graph.entities[i].members, function(e) {
                        return e.id === id;
                    })) {
                    o.push(graph.entities[i]);
                }
            }
            return o;
        });
    },

    merge: function(graph) {
        var entities = _.clone(this.entities);
        _.defaults(entities, graph.entities);
        return iD.Graph(entities);
    },

    replace: function(entity) {
        var entities = _.clone(this.entities);
        entities[entity.id] = entity;
        return iD.Graph(entities);
    },

    remove: function(entity) {
        var entities = _.clone(this.entities);

        if (entity.created()) {
            delete entities[entity.id];
        } else {
            entities[entity.id] = undefined;
        }

        return iD.Graph(entities);
    },

    // get all objects that intersect an extent.
    intersects: function(extent) {
        var items = [];
        for (var i in this.entities) {
            var entity = this.entities[i];
            if (entity && entity.intersects(extent, this)) {
                items.push(this.fetch(entity.id));
            }
        }
        return items;
    },

    // Resolve the id references in a way, replacing them with actual objects.
    fetch: function(id) {
        var entity = this.entities[id], nodes = [];
        if (!entity || !entity.nodes || !entity.nodes.length) return entity;
        for (var i = 0, l = entity.nodes.length; i < l; i++) {
            nodes[i] = this.fetch(entity.nodes[i]);
        }
        return iD.Entity(entity, {nodes: nodes});
    },

    difference: function (graph) {
        var result = [], entity, id;

        for (id in this.entities) {
            entity = this.entities[id];
            if (entity !== graph.entities[id]) {
                result.push(id);
            }
        }

        for (id in graph.entities) {
            entity = graph.entities[id];
            if (entity && !this.entities.hasOwnProperty(id)) {
                result.push(id);
            }
        }

        return result.sort();
    },

    modified: function() {
        var result = [];
        _.each(this.entities, function(entity, id) {
            if (entity && entity.modified()) result.push(id);
        });
        return result;
    },

    created: function() {
        var result = [];
        _.each(this.entities, function(entity, id) {
            if (entity && entity.created()) result.push(id);
        });
        return result;
    },

    deleted: function() {
        var result = [];
        _.each(this.entities, function(entity, id) {
            if (!entity) result.push(id);
        });
        return result;
    }
};

@@ -357,16 +357,43 @@
 ts = %7B%7D;
+%0A    this._parentWays = %7B%7D;
 %0A%0A    if
@@ -947,16 +947,19 @@
      ent
+ity
 ,%0A      
@@ -964,20 +964,18 @@
         
-node
+id
 ;%0A%0A     
@@ -1075,16 +1075,19 @@
      ent
+ity
  = graph
@@ -1123,23 +1123,29 @@
  if (ent
+ity
  && ent
+ity
 .type ==
@@ -1198,16 +1198,19 @@
  j %3C ent
+ity
 .nodes.l
@@ -1251,33 +1251,19 @@
     
-node = graph.entities%5Bent
+id = entity
 .nod
@@ -1267,17 +1267,16 @@
 nodes%5Bj%5D
-%5D
 ;%0A      
@@ -1297,41 +1297,51 @@
     
-node.
+this._
 parent
-ways = node.
+Ways%5Bid%5D = this._
 parent
-w
+W
 ays
+%5Bid%5D
  %7C%7C 
@@ -1372,31 +1372,36 @@
     if (
-node.
+this._
 parent
-w
+W
 ays
+%5Bid%5D
 .indexOf
@@ -1404,16 +1404,19 @@
 exOf(ent
+ity
 ) %3C 0) %7B
@@ -1448,23 +1448,28 @@
     
-node.
+this._
 parent
-w
+W
 ays
+%5Bid%5D
 .pus
@@ -1473,16 +1473,19 @@
 push(ent
+ity
 );%0A     
@@ -1636,25 +1636,35 @@
 urn 
-entity.
+this._
 parent
-w
+W
 ays
+%5Bentity.id%5D
  %7C%7C 

clean up parentWays