diff --git a/js/panes/contact/contactPane.js b/js/panes/contact/contactPane.js
index 00eadfa..e408c2a 100644
--- a/js/panes/contact/contactPane.js
+++ b/js/panes/contact/contactPane.js
@@ -22,203 +22,6 @@ if (typeof console == 'undefined') { // e.g. firefox extension. Node and browser
 
 
 
-//////////////////////////////////////////////////////  SUBCRIPTIONS
-
-$rdf.subscription =  function(options, doc, onChange) {
-
-
-    //  for all Link: uuu; rel=rrr  --->  { rrr: uuu }
-    var linkRels = function(doc) {
-        var links = {}; // map relationship to uri
-        var linkHeaders = tabulator.fetcher.getHeader(doc, 'link');
-        if (!linkHeaders) return null;
-        linkHeaders.map(function(headerValue){
-            var arg = headerValue.trim().split(';');
-            var uri = arg[0];
-            arg.slice(1).map(function(a){
-                var key = a.split('=')[0].trim();
-                var val = a.split('=')[1].trim();
-                if (key ==='rel') {
-                    links[val] = uri.trim();
-                }
-            });        
-        });
-        return links;
-    };
-
-
-    var getChangesURI = function(doc, rel) {
-        var links = linkRels(doc);
-        if (!links[rel]) {
-            console.log("No link header rel=" + rel + " on " + doc.uri)
-            return null;
-        }
-        var changesURI = $rdf.uri.join(links[rel], doc.uri);
-        // console.log("Found rel=" + rel + " URI: " + changesURI);
-        return changesURI;
-    };
-
-
-
-///////////////  Subscribe to changes by SSE
-
-
-    var getChanges_SSE = function(doc, onChange) {
-        var streamURI = getChangesURI(doc, 'events');
-        if (!streamURI) return;
-        var source = new EventSource(streamURI); // @@@  just path??
-        console.log("Server Side Source");   
-
-        source.addEventListener('message', function(e) {
-            console.log("Server Side Event: " + e);   
-            alert("SSE: " + e)  
-            // $('ul').append('
' + e.data + ' (message id: ' + e.lastEventId + ')');
-        }, false);
-    };
-
- 
-    
-
-    //////////////// Subscribe to changes websocket
-
-    // This implementation uses web sockets using update-via
-    
-    var getChanges_WS2 = function(doc, onChange) {
-        var router = new $rdf.UpdatesVia(tabulator.fetcher); // Pass fetcher do it can subscribe to headers
-        var wsuri = getChangesURI(doc, 'changes').replace(/^http:/, 'ws:').replace(/^https:/, 'wss:');
-        router.register(wsuri, doc.uri);
-    };
-    
-    
-    var getChanges_WS = function(doc, onChange) {
-        var SQNS = $rdf.Namespace('http://www.w3.org/ns/pim/patch#');
-        var changesURI = getChangesURI(doc, 'updates'); //  @@@@ use single
-        var socket;
-        try {
-            socket = new WebSocket(changesURI);
-        } catch(e) {
-            socket = new MozWebSocket(changesURI);
-        };
-        
-        socket.onopen = function(event){
-            console.log("socket opened");
-        };
-        
-        socket.onmessage = function (event) {
-            console.log("socket received: " +event.data);
-            var patchText = event.data;
-            console.log("Success: patch received:" + patchText);
-            
-            // @@ check integrity of entire patch
-            var patchKB = $rdf.graph();
-            var sts;
-            try {
-                $rdf.parse(patchText, patchKB, doc.uri, 'text/n3');
-            } catch(e) {
-                console.log("Parse error in patch: "+e);
-            };
-            clauses = {};
-            ['where', 'insert', 'delete'].map(function(pred){
-                sts = patchKB.statementsMatching(undefined, SQNS(pred), undefined);
-                if (sts) clauses[pred] = sts[0].object;
-            });
-            console.log("Performing patch!");
-            kb.applyPatch(clauses, doc, function(err){
-                if (err) {
-                    console.log("Incoming patch failed!!!\n" + err)
-                    alert("Incoming patch failed!!!\n" + err)
-                    socket.close();
-                } else {
-                    console.log("Incoming patch worked!!!!!!\n" + err)
-                    onChange(); // callback user
-                };
-            });
-        };
-
-    }; // end getChanges
-    
-
-    ////////////////////////// Subscribe to changes using Long Poll
-
-    // This implementation uses link headers and a diff returned by plain HTTP
-    
-    var getChanges_LongPoll = function(doc, onChange) {
-        var changesURI = getChangesURI(doc, 'changes');
-        if (!changesURI) return "No advertized long poll URI";
-        console.log(tabulator.panes.utils.shortTime() + " Starting new long poll.")
-        var xhr = $rdf.Util.XMLHTTPFactory();
-        xhr.alreadyProcessed = 0;
-
-        xhr.onreadystatechange = function(){
-            switch (xhr.readyState) {
-            case 0:
-            case 1:
-                return;
-            case 3:
-                console.log("Mid delta stream (" + xhr.responseText.length + ") "+ changesURI);
-                handlePartial();
-                break;
-            case 4:
-                handlePartial();
-                console.log(tabulator.panes.utils.shortTime() + " End of delta stream " + changesURI);
-                break;
-             }   
-        };
-
-        try {
-            xhr.open('GET', changesURI);
-        } catch (er) {
-            console.log("XHR open for GET changes failed <"+changesURI+">:\n\t" + er);
-        }
-        try {
-            xhr.send();
-        } catch (er) {
-            console.log("XHR send failed <"+changesURI+">:\n\t" + er);
-        }
-
-        var handlePartial = function() {
-            // @@ check content type is text/n3
-
-            if (xhr.status >= 400) {
-                console.log("HTTP (" + xhr.readyState + ") error " + xhr.status + "on change stream:" + xhr.statusText);
-                console.log("     error body: " + xhr.responseText);
-                xhr.abort();
-                return;
-            } 
-            if (xhr.responseText.length > xhr.alreadyProcessed) {
-                var patchText = xhr.responseText.slice(xhr.alreadyProcessed);
-                xhr.alreadyProcessed = xhr.responseText.length;
-                
-                console.log(tabulator.panes.utils.shortTime() + " Long poll returns, processing...")
-                xhr.headers = $rdf.Util.getHTTPHeaders(xhr);
-                try {
-                    onChange(patchText);
-                } catch (e) {
-                    console.log("Exception in patch update handler: " + e)
-                    // @@ Where to report error e?
-                }
-                getChanges_LongPoll(doc, onChange); // Queue another one
-                
-            }        
-        };
-        return null; // No error
-
-    }; // end getChanges_LongPoll
-    
-    if (options.longPoll ) {
-        getChanges_LongPoll(doc, onChange);
-    }
-    if (options.SSE) {
-        getChanges_SSE(doc, onChange);
-    }
-    if (options.websockets) {
-        getChanges_WS(doc, onChange);
-    }
-
-}; // subscription
-
-/////////////////////////////////////////// End of subscription stufff 
-
 // Sets the best name we have and looks up a better one
 tabulator.panes.utils.setName = function(element, subject) {
     var kb = tabulator.kb, ns = tabulator.ns;
@@ -271,15 +74,15 @@ tabulator.panes.utils.deleteButtonWithCheck = function(dom, container, noun, del
 
 tabulator.panes.utils.adoptACLDefault = function(doc, aclDoc, defaultResource, defaultACLdoc) {
     var kb = tabulator.kb;
-    var auth = tabulator.ns.auth;
+    var ACL = tabulator.ns.acl;
     var ns = tabulator.ns;
-    var defaults = kb.each(undefined, auth('defaultForNew'), defaultResource, defaultACLdoc);
+    var defaults = kb.each(undefined, ACL('defaultForNew'), defaultResource, defaultACLdoc);
     var proposed = [];
     defaults.map(function(da) {
-        proposed = proposed.concat(kb.statementsMatching(da, auth('agent'), undefined, defaultACLdoc))
-            .concat(kb.statementsMatching(da, auth('agentClass'), undefined, defaultACLdoc))
-            .concat(kb.statementsMatching(da, auth('mode'), undefined, defaultACLdoc));
-        proposed.push($rdf.st(da, auth('accessTo'), doc, defaultACLdoc)); // Suppose 
+        proposed = proposed.concat(kb.statementsMatching(da, ACL('agent'), undefined, defaultACLdoc))
+            .concat(kb.statementsMatching(da, ACL('agentClass'), undefined, defaultACLdoc))
+            .concat(kb.statementsMatching(da, ACL('mode'), undefined, defaultACLdoc));
+        proposed.push($rdf.st(da, ACL('accessTo'), doc, defaultACLdoc)); // Suppose 
     });
     var kb2 = $rdf.graph(); // Potential - derived is kept apart
     proposed.map(function(st){
@@ -292,29 +95,177 @@ tabulator.panes.utils.adoptACLDefault = function(doc, aclDoc, defaultResource, d
     });
     
     //   @@@@@ ADD TRIPLES TO ACCES CONTROL ACL FILE -- until servers fixed @@@@@
-    var ccc = kb2.each(undefined, auth('accessTo'), doc)
-        .filter(function(au){ return  kb2.holds(au, auth('mode'), auth('Control'))});
+    var ccc = kb2.each(undefined, ACL('accessTo'), doc)
+        .filter(function(au){ return  kb2.holds(au, ACL('mode'), ACL('Control'))});
     ccc.map(function(au){
         var au2 = kb2.sym(au.uri + "__ACLACL");
-            kb2.add(au2, ns.rdf('type'), auth('Authorization'), aclDoc);
-            kb2.add(au2, auth('accessTo'), aclDoc, aclDoc);
-            kb2.add(au2, auth('mode'), auth('Read'), aclDoc);
-            kb2.add(au2, auth('mode'), auth('Write'), aclDoc);
-        kb2.each(au, auth('agent')).map(function(who){
-            kb2.add(au2, auth('agent'), who, aclDoc);
+            kb2.add(au2, ns.rdf('type'), ACL('Authorization'), aclDoc);
+            kb2.add(au2, ACL('accessTo'), aclDoc, aclDoc);
+            kb2.add(au2, ACL('mode'), ACL('Read'), aclDoc);
+            kb2.add(au2, ACL('mode'), ACL('Write'), aclDoc);
+        kb2.each(au, ACL('agent')).map(function(who){
+            kb2.add(au2, ACL('agent'), who, aclDoc);
         });
-        kb2.each(au, auth('agentClass')).map(function(who){
-            kb2.add(au2, auth('agentClass'), who, aclDoc);
+        kb2.each(au, ACL('agentClass')).map(function(who){
+            kb2.add(au2, ACL('agentClass'), who, aclDoc);
         });
     });
     
     return kb2;
 }
 
+
+// Read and conaonicalize the ACL for x in aclDoc
+//
+// Accumulate the access rights which each agent or class has
+//
+tabulator.panes.utils.readACL = function(x, aclDoc) {
+    var ac = {'agent': [], 'agentClass': []};
+    var auths = kb.each(undefined, ACL('acccessTo'), x);
+    for (var pred in ['agent', 'agentClass']) {
+        auths.map(function(a){
+            kb.each(a,  ACL('mode')).map(function(mode){
+                 kb.each(a,  ACL('agent')).map(function(agent){
+                 
+                    if (!ac[pred][agent]) ac[pred][agent] = [];
+                    ac[pred][agent][mode] = true;
+                    agents[mode][agent] = a;
+                });
+            });
+        });
+    }
+    return ac;
+}
+
+// Compare two ACLs
+tabulator.panes.utils.sameACL = function(a, b) {
+    var contains = function(a, b) {
+        ['agent', 'agentClass'].map(function(pred){
+            if (a[pred]) {
+                for (var ag in a[pred]) {
+                    for (var mode in a[pred][agent]) {
+                        if (!b[pred][agent] || !b[pred][agent][mode]) {
+                            return false;
+                        }
+                    }
+                }
+            };
+        });
+        return true;
+    }
+    return contains(a, b) && contains(b,a);
+}
+
+// Union N ACLs
+tabulator.panes.utils.ACLunion = function(list) {
+    var b = list[0];
+    for (var k=1; k < list.length; k++) {
+        ['agent', 'agentClass'].map(function(pred){
+            if (a[pred]) {
+                for (var ag in a[pred]) {
+                    for (var mode in a[pred][ag]) {
+                        if (!b[pred][ag]) b[pred][ag] = [];
+                        b[pred][ag][mode] = true;
+                    }
+                }
+            };
+        });
+    }
+    return b;
+}
+
+
+// Merge ACLs lists from things to form union
+
+tabulator.panes.utils.loadUnionACL = function(subjectList, callback) {
+    var aclList = [];
+    var doList = function(list) {
+        if (list.length) {
+            doc = list.shift();
+            tabulator.panes.utils.getACLorDefault(list[0], function(ok, defa, p3, p4, defaultHolder, defaultACLDoc){
+                if (!ok) return callback(ok, p4);
+                acList.append((defa) ? tabulator.panes.utils.readACL(defaultHolder, defaultACLDoc) :
+                    tabulator.panes.utils.readACL(p3, p4));
+                doList(list.slice(1));
+            });
+        } else { // all gone
+            callback(true, tabulator.panes.utils.ACLunion(aclList))
+        }
+    }
+    doList(subjectList);
+}
+
+// Represents these as a RDF graph by combination of modes
+//
+tabulator.panes.utils.writeACL = function(kb, x, ac, aclDoc) {
+    var byCombo = [];
+    for (var pred in ['agent', 'agentClass']) {
+        for (var agent in ac[pred]) {
+            if (ac[pred][agent]) for (var agent in ac[pred][agent]) {
+                var modes = ac[pred][agent];
+                var combo = [];
+                for (var mode in ac[pred][agent]) {
+                    combo.append(mode.fromNT.uri) //
+                }
+                combo.sort()
+                combo = combo.join('\n'); 
+                if (!byCombo[combo]) byCombo[combo] = [];
+                byCombo[combo].append([pred, agent])
+            }
+        }
+    }
+    for (combo in byCombo) {
+        var a = kb.sym(aclDoc.uri + '#' + combo);
+        kb.add(a, tabulator.ns.rdf('type'), ACL('Authorization'), aclDoc);
+        var m = combo.split('\n');
+        for (var i=0; i < m.length; i++) {
+            kb.add(a, ACL('mode'), kb.sym(m[i]), aclDoc);
+        }
+        var pairs = byCombo[combo];
+        for (i=0; i< pairs.length; i++) {
+            var p = pairs[0], ag = pairs[1];
+            kb.add(a, ACL(p), kb.sym(ag), aclDoc);
+        } 
+        
+    }
+}
+
+// Fix the ACl for an individual card as a function of the groups it is in
+// 
+// All group files must be loaded first
+//
+
+tabulator.panes.utils.fixIndividualCardACL = function(person, callback)  {
+    var groups =  tabulator.kb.each(undefined, tabulator.ns.vcard('hasMember'), person); 
+    if (groups) {
+        tabulator.panes.utils.fixIndividualACL(person.doc(), groups, callback);
+    }
+    // @@ if no groups, then use default for People container or the book top container.
+}
+
+tabulator.panes.utils.fixIndividualACL = function(doc, subjects, callback)  {
+    tabulator.panes.utils.getACLorDefault(doc, function(ok, defa, p3, p4, defaultHolder, defaultACLDoc){ 
+        if (!ok) return callback(ok, p4);
+        var ac = (defa) ? tabulator.panes.utils.readACL(defaultHolder, defaultACLDoc) :
+            tabulator.panes.utils.readACL(p3, p4);
+        tabulator.panes.utils.loadUnionACL(subjects, function(ok, union){
+            if (tabulator.panes.utils.sameACL(union, ac)) {
+                console.log("Nice - same ACL. no change " + doc);
+            } else {
+                console.log("Group ACLs differ for " + doc);
+                console.log("Group ACLs " + union + "\n");
+                console.log((defa ? "Default" : "Previous set") + " ACLs " + ac + "\n");
+                // @@@ TBD
+                // serialize and store ACL.
+            }
+        });
+    })
+}
+
 tabulator.panes.utils.ACLControlBox = function(subject, dom, callback) {
     var kb = tabulator.kb;
     var updater = new tabulator.rdf.sparqlUpdate(kb);
-    var auth = tabulator.ns.auth;
+    var ACL = tabulator.ns.acl;
     var doc = $rdf.sym(subject.uri.split('#')[0]); // The ACL is actually to the doc describing the thing
 
     var table = dom.createElement('table');
@@ -331,15 +282,15 @@ tabulator.panes.utils.ACLControlBox = function(subject, dom, callback) {
     var bottomRow = table.appendChild(dom.createElement('tr'));
 
     var ACLControl = function(box, doc, aclDoc, kb) {
-        var authorizations = kb.each(undefined, auth('accessTo'), doc, aclDoc); // ONLY LOOK IN ACL DOC
+        var authorizations = kb.each(undefined, ACL('accessTo'), doc, aclDoc); // ONLY LOOK IN ACL DOC
         if (authorizations.length === 0) {
             statusBlock.textContent += "Access control file exists but contains no authorizations! " + aclDoc + ")";
         }
         for (i=0; i < authorizations.length; i++) {
             var row = box.appendChild(dom.createElement('tr'));
             var rowdiv1 = row.appendChild(dom.createElement('div'));
-            row.setAttribute('style', 'margin: 1em; border: 0.1em solid black; border-radius: 0.5em; padding: 1em;') // doesn't work
-            rowdiv1.setAttribute('style', 'margin: 1em; border: 0.1em solid black; border-radius: 1em; padding: 1em;');
+
+            rowdiv1.setAttribute('style', 'margin: 1em; border: 0.1em solid #444; border-radius: 0.5em; padding: 1em;');
             rowtable1 = rowdiv1.appendChild(dom.createElement('table'));
             rowrow = rowtable1.appendChild(dom.createElement('tr'));
             var left = rowrow.appendChild(dom.createElement('td'));
@@ -351,44 +302,105 @@ tabulator.panes.utils.ACLControlBox = function(subject, dom, callback) {
             var rightTable = right.appendChild(dom.createElement('table'));
             var a = authorizations[i];
             
-            kb.each(a,  auth('agent')).map(function(x){
+            kb.each(a,  ACL('agent')).map(function(x){
                 var tr = leftTable.appendChild(dom.createElement('tr'));
                 tabulator.panes.utils.setName(tr, x);
                 tr.setAttribute('style', 'min-width: 12em');
             });
             
-            kb.each(a,  auth('agentClass')).map(function(x){
+            kb.each(a,  ACL('agentClass')).map(function(x){
                 var tr = leftTable.appendChild(dom.createElement('tr'));
                 tr.textContent = tabulator.Util.label(x) + ' *'; // for now // later add # or members
             });
             
-            kb.each(a,  auth('mode')).map(function(x){
+            kb.each(a,  ACL('mode')).map(function(x){
                 var tr = rightTable.appendChild(dom.createElement('tr'));
                 tr.textContent = tabulator.Util.label(x); // for now // later add # or members
             });
         }
     }
 
-    tabulator.panes.utils.getACL(doc, function(ok, status, aclDoc, message) {
-        var i, row, left, right, a;
-        var auth = tabulator.ns.auth;
-        var useDefault;
-        var addDefaultButton = function() {
-            useDefault = bottomRow.appendChild(dom.createElement('button'));
-            useDefault.textContent = "Stop specific sharing for this group -- just use default.";
-            useDefault.addEventListener('click', function(event) {
-                updater.delete(doc, function(uri, ok, message){
-                    if (!ok) {
-                        statusBlock.textContent += " (Error deleting access control file: "+message+")";
-                    } else {
-                        statusBlock.textContent = " The sharing for this group is now the default.";
-                        bottomRow.removeChild(useDefault);
-                    }
-                });
 
-            });
+    tabulator.panes.utils.getACLorDefault(doc, function(ok, defa, p3, p4, defaultHolder, defaultACLDoc){
+        if (!ok) {
+            statusBlock.textContent += "Error reading " + (defa? " default " : "") + "ACL."
+                + " status " + p3 + ": " + p4;
+        } else {
+            if (defa) {
+                var defaults = kb.each(undefined, ACL('defaultForNew'), defaultHolder, defaultACLDoc);
+                if (!defaults.length) {
+                    statusBlock.textContent += " (No defaults given.)";
+                } else {
+                    statusBlock.textContent = "The sharing for this group is the default.";
+                    var kb2 = tabulator.panes.utils.adoptACLDefault(doc, aclDoc, defaultHolder, defaultACLDoc) 
+                    ACLControl(box, doc, aclDoc, kb2); // Add btton to save them as actual
+                    
+                    var editPlease = bottomRow.appendChild(dom.createElement('button'));
+                    editPlease.textContent = "Set specific sharing\nfor this group";
+                    editPlease.addEventListener('click', function(event) {
+                        updater.put(aclDoc, kb2.statements,
+                            'text/turtle', function(uri, ok, message){
+                            if (!ok) {
+                                statusBlock.textContent += " (Error writing back access control file: "+message+")";
+                            } else {
+                                statusBlock.textContent = " (Now editing specific access for this group)";
+                                bottomRow.removeChild(editPlease);
+                            }
+                        });
+
+                    });
+                } // defaults.length
+            } else { // Not using defaults
+
+                ACLControl(box, p3, p4, kb);
+                addDefaultButton();
+            
+            } // Not using defaults
         }
+            
+    });
+
+    return table
+    
+}; // ACLControl
+
+
+tabulator.panes.utils.setACL = function(docURI, aclText, callback) {
+    var aclDoc = kb.any(kb.sym(docURI),
+        kb.sym('http://www.iana.org/assignments/link-relations/acl')); // @@ check that this get set by web.js
+    if (aclDoc) { // Great we already know where it is
+        webOperation('PUT', aclDoc.uri, { data: aclText, contentType: 'text/turtle'}, callback);        
+    } else {
+    
+        fetcher.nowOrWhenFetched(docURI, undefined, function(ok, body){
+            if (!ok) return callback(ok, "Gettting headers for ACL: " + body);
+            var aclDoc = kb.any(kb.sym(docURI),
+                kb.sym('http://www.iana.org/assignments/link-relations/acl')); // @@ check that this get set by web.js
+            if (!aclDoc) {
+                // complainIfBad(false, "No Link rel=ACL header for " + docURI);
+                callback(false, "No Link rel=ACL header for " + docURI);
+            } else {
+                webOperation('PUT', aclDoc.uri, { data: aclText, contentType: 'text/turtle'}, callback);
+            }
+        })
+    }
+};
+
 
+//  Get ACL file or default if necessary
+//
+// callback(true, true, doc, aclDoc)   The ACL did exist
+// callback(true, false, doc, aclDoc, defaultHolder, defaultACLDoc)   ACL file did not exist but a default did
+// callback(false, false, status, message)  error getting original
+// callback(false, true, status, message)  error getting defualt
+
+tabulator.panes.utils.getACLorDefault = function(doc, callback) {
+
+    tabulator.panes.utils.getACL(doc, function(ok, status, aclDoc, message) {
+        var i, row, left, right, a;
+        var kb = tabulator.kb;
+        var ACL = tabulator.ns.acl;
+        if (!ok) return callback(false, false, status, message);
         
         // Recursively search for the ACL file which gives default access
         var tryParent = function(uri) {
@@ -399,91 +411,48 @@ tabulator.panes.utils.ACLControlBox = function(subject, dom, callback) {
             var left = uri.indexOf('/', uri.indexOf('//') + 2);
             uri = uri.slice(0, right + 1);
             var doc2 = $rdf.sym(uri);
-            tabulator.panes.utils.getACL(doc2, function(ok, status, aclDoc2) {
+            tabulator.panes.utils.getACL(doc2, function(ok, status, defaultACLDoc) {
 
                 if (!ok) {
-                    statusBlock.textContent += ("( No ACL pointer " + uri + ' ' + status + ")");
+                    return callback(false, true, status, "( No ACL pointer " + uri + ' ' + status + ")")
                 } else if (status === 403) {
-                    statusBlock.textContent += ("( ACL file FORBIDDEN. Stop." + uri + ")");
+                    return callback(false, true, status,"( default ACL file FORBIDDEN. Stop." + uri + ")");
                 } else if (status === 404) {
-                    statusBlock.textContent += ("( No ACL file for set " + uri + ")");
                     if (left >= right) {
-                        statusBlock.textContent += ("( Thats all folks.)");
+                        return callback(false, true, 499, "Nothing to hold a default");
                     } else {
                         tryParent(uri);
                     }
+                } else if (status !== 200) {
+                        return callback(false, true, status, "Error searching for default");
                 } else { // 200
-                    statusBlock.textContent += (" ACCESS set at " + uri + ". End search.");
-                    var defaults = kb.each(undefined, auth('defaultForNew'), kb.sym(uri), aclDoc2);
+                    //statusBlock.textContent += (" ACCESS set at " + uri + ". End search.");
+                    var defaults = kb.each(undefined, ACL('defaultForNew'), kb.sym(uri), defaultACLDoc);
                     if (!defaults.length) {
-                        statusBlock.textContent += " (No defaults given.)";
+                        tryParent(uri);       // Keep searching
                     } else {
-                        statusBlock.textContent = "The sharing for this group is the default.";
-                        var kb2 = tabulator.panes.utils.adoptACLDefault(doc, aclDoc, kb.sym(uri), aclDoc2) 
-                        ACLControl(box, doc, aclDoc, kb2); // Add btton to save them as actual
-                        
-                        var editPlease = bottomRow.appendChild(dom.createElement('button'));
-                        editPlease.textContent = "Set specific sharing\nfor this group";
-                        editPlease.addEventListener('click', function(event) {
-                            updater.put(aclDoc, kb2.statements,
-                                'text/turtle', function(uri, ok, message){
-                                if (!ok) {
-                                    statusBlock.textContent += " (Error writing back access control file: "+message+")";
-                                } else {
-                                    statusBlock.textContent = " (Now editing specific access for this group)";
-                                    bottomRow.removeChild(editPlease);
-                                }
-                            });
-
-                        });
+                        var defaultHolder = kb.sym(uri);
+                        callback(true, false, doc, aclDoc, defaultHolder, defaultACLDoc)
                     }
                 }
             });
-        };
+        }; // tryParent
 
         if (!ok) {
-            statusBlock.textContent += ("( Access control information not provided " + uri +")");
+            return callback(false, false, status , "Error accessing Access Control information for " + uri +")");
         } else if (status === 404) {
-            statusBlock.textContent = '(No specific access control has been set.)\n'; // error message
-            statusBlock.setAttribute('style', 'background-color: #ffe; padding:2em;');
-            tryParent(doc.uri);
-            //  @@ construct default one - the server should do that
+            tryParent(doc.uri);   //  @@ construct default one - the server should do that
         } else  if (status === 403) {
-            statusBlock.textContent = '(Sharing not available to you)'; // error message
+            return callback(false, false, status, "(Sharing not available to you)");
         } else  if (status !== 200) {
-            statusBlock.textContent = message; // error message
-            statusBlock.setAttribute('style', 'background-color: #f99; padding:2em;')
+            return callback(false, false, status, "Error " + status + " accessing Access Control information for " + uri); 
         } else { // 200
-            ACLControl(box, doc, aclDoc, kb);
-            addDefaultButton();
-        }        
-    });
-    
-    return table
-}; // ACLControl
+            return callback(true, true, doc, aclDoc);
+        }  
+    }); // Call to getACL
+} // getACLorDefault
 
 
-tabulator.panes.utils.setACL = function(docURI, aclText, callback) {
-    var aclDoc = kb.any(kb.sym(docURI),
-        kb.sym('http://www.iana.org/assignments/link-relations/acl')); // @@ check that this get set by web.js
-    if (aclDoc) { // Great we already know where it is
-        webOperation('PUT', aclDoc.uri, { data: aclText, contentType: 'text/turtle'}, callback);        
-    } else {
-    
-        fetcher.nowOrWhenFetched(docURI, undefined, function(ok, body){
-            if (!ok) return callback(ok, "Gettting headers for ACL: " + body);
-            var aclDoc = kb.any(kb.sym(docURI),
-                kb.sym('http://www.iana.org/assignments/link-relations/acl')); // @@ check that this get set by web.js
-            if (!aclDoc) {
-                // complainIfBad(false, "No Link rel=ACL header for " + docURI);
-                callback(false, "No Link rel=ACL header for " + docURI);
-            } else {
-                webOperation('PUT', aclDoc.uri, { data: aclText, contentType: 'text/turtle'}, callback);
-            }
-        })
-    }
-};
-
 //    Calls back (ok, status, acldoc, message)
 // 
 //   (false, errormessage)        no link header
@@ -574,9 +543,9 @@ tabulator.panes.register( {
         } 
 
         var complainIfBad = function(ok,body){
-            if (ok) {
+            if (!ok) {
+                console.log("Error: " + body);
             }
-            else console.log("Sorry, failed to save your change:\n"+body, 'background-color: pink;');
         }
 
         var getOption = function (tracker, option){ // eg 'allowSubContacts'
@@ -966,7 +935,7 @@ tabulator.panes.register( {
            // Write new group to web
            // Creates an empty new group file and adds it to the index
            //
-           var createNewGroup = function(book, name, callback) {
+           var saveNewGroup = function(book, name, callback) {
                 var gix = kb.any(book, ns.vcard('groupIndex'));
                 
                 var x = subject.uri.split('#')[0]
@@ -1060,6 +1029,25 @@ tabulator.panes.register( {
                     return name ? name.value : '???';
                 }
                 
+                var filterName = function(name) {
+                    var filter = searchInput.value.trim().toLowerCase();
+                    if (filter.length === 0) return true;
+                    var parts = filter.split(' '); // Each name part must be somewhere
+                    for (var j=0; j< parts.length; j++) {
+                        word = parts[j];
+                        if (name.toLowerCase().indexOf(word) <0 ) return false;
+                    }
+                    return true;
+                }
+                
+                var searchFilterNames = function() {
+                    for (var i=0; i < peopleMainTable.children.length; i++) {
+                        row = peopleMainTable.children[i] 
+                        row.setAttribute('style',
+                            filterName(nameFor(row.subject)) ? '' : 'display: none;');
+                    }
+                }
+
                 var bookTable = dom.createElement('table');
                 bookTable.setAttribute('style', 'border-collapse: collapse; margin-right: 0;')
                 div.appendChild(bookTable);
@@ -1078,17 +1066,53 @@ tabulator.panes.register( {
                 var peopleFooter =  bookFooter.appendChild(dom.createElement('td'));
                 var cardFooter =  bookFooter.appendChild(dom.createElement('td'));
                 
+                var  searchDiv = cardHeader.appendChild(dom.createElement('div'));
+                // searchDiv.setAttribute('style', 'border: 0.1em solid #888; border-radius: 0.5em');
+                searchInput = cardHeader.appendChild(dom.createElement('input'));
+                searchInput.setAttribute('type', 'text');
+                searchInput.setAttribute('style', 'border: 0.1em solid #444; border-radius: 0.5em; width: 100%;');
+                // searchInput.addEventListener('input', searchFilterNames);
+                searchInput.addEventListener('input', function(e){
+                    searchFilterNames();
+                });
+
                 var cardMain = bookMain.appendChild(dom.createElement('td'));
                 cardMain.setAttribute('style', 'margin: 0;'); // fill space available
                 var dataCellStyle =  'padding: 0.1em;'
                 
                 groupsHeader.textContent = "groups";
                 groupsHeader.setAttribute('style', 'min-width: 10em; padding-bottom 0.2em;');
+                var allGroups = groupsHeader.appendChild(dom.createElement('button'));
+                allGroups.textContent = "All";
+                allGroups.setAttribute('style', 'margin-left: 1em;');
+                allGroups.addEventListener('click', function(event){
+                    allGroups.state = allGroups.state ? 0 : 1;
+                    peopleMainTable.innerHTML = ''; // clear in case refreshNames doesn't work for unknown reason
+                    if (allGroups.state) {
+                        for (var k=0; k < groupsMainTable.children.length; k++) {
+                            var groupRow = groupsMainTable.children[k];
+                            var group = groupRow.subject;
+
+                            var groupList = kb.sym(group.uri.split('#')[0]);
+                            selected[group.uri] = true;
+
+                            kb.fetcher.nowOrWhenFetched(groupList.uri, undefined, function(ok, message){
+                                if (!ok) return complainIfBad(ok, "Can't load group file: " +  groupList + ": " + message);
+                                groupRow.setAttribute('style', 'background-color: #cce;');
+                                refreshNames(); // @@ every time??
+                            });
+                        //refreshGroups();
+                        } // for each row
+                    } else {
+                        selected = {};
+                        refreshGroups();
+                    }
+                }); // on button click
+
                 
                 peopleHeader.textContent = "name";
                 peopleHeader.setAttribute('style', 'min-width: 18em;');
                 peopleMain.setAttribute('style','overflow:scroll;');
-                // cardHeader.textContent = "contact details"; // clutter
                 
                 
                 var groups = kb.each(subject, ns.vcard('includesGroup'));
@@ -1099,7 +1123,7 @@ tabulator.panes.register( {
                 var cardPane = function(dom, subject, paneName) {
                     var p = tabulator.panes.byName(paneName);
                     var d = p.render(subject, dom);
-                    d.setAttribute('style', 'border: 0.1em solid #888; border-radius: 0.5em')
+                    d.setAttribute('style', 'border: 0.1em solid #444; border-radius: 0.5em')
                     return d;
                 };
 
@@ -1156,19 +1180,29 @@ tabulator.panes.register( {
                         }
                     }
                     cards.sort(compareForSort); // @@ sort by name not UID later
+                    for (var k=0; k < cards.length - 1;) {
+                        if (cards[k].uri === cards[k+1].uri) {
+                            cards.splice(k,1);
+                        } else {
+                            k++;
+                        }
+                    }
+                    
                     peopleMainTable.innerHTML = ''; // clear
                     peopleHeader.textContent = (cards.length > 5 ? '' + cards.length + " contacts" : "contact");
 
                     for (var j =0; j < cards.length; j++) {
                         var personRow = peopleMainTable.appendChild(dom.createElement('tr'));
-                        personRow.setAttribute('style', dataCellStyle);
+                        var personLeft = personRow.appendChild(dom.createElement('td'));
+                        var personRight = personRow.appendChild(dom.createElement('td'));
+                        personLeft.setAttribute('style', dataCellStyle);
                         var person = cards[j];
                         var name = nameFor(person);
-                        personRow.textContent = name;
+                        personLeft.textContent = name;
                         personRow.subject = person;
 
-                        var setPersonListener = function toggle(personRow, person) {
-                            tabulator.panes.utils.deleteButtonWithCheck(dom, personRow, 'contact', function(){
+                        var setPersonListener = function toggle(personLeft, person) {
+                            tabulator.panes.utils.deleteButtonWithCheck(dom, personRight, 'contact', function(){
                                 deleteThing(person);
                                 refreshNames();
                                 cardMain.innerHTML = '';
@@ -1181,12 +1215,17 @@ tabulator.panes.register( {
                                     cardMain.innerHTML = '';
                                     if (!ok) return complainIfBad(ok, "Can't load card: " +  group.uri.split('#')[0] + ": " + message)
                                     // dump("Loaded card " + cardURI + '\n')
-                                    cardMain.appendChild(cardPane(dom, person, 'contact'));            
+                                    cardMain.appendChild(cardPane(dom, person, 'contact'));  
+                                    cardMain.appendChild(dom.createElement('br'));
+                                    var anchor = cardMain.appendChild(dom.createElement('a'));
+                                    anchor.setAttribute('href', person.uri);
+                                    anchor.textContent = '->';
                                 })
                            });
                         };
                         setPersonListener(personRow, person);
                     };
+                    searchFilterNames();
     
                 }
                 
@@ -1209,10 +1248,8 @@ tabulator.panes.register( {
                     // var groupLeft = groupRow.appendChild(dom.createElement('td'));
                     // var groupRight = groupRow.appendChild(dom.createElement('td'));
                     groupRow.textContent = name;
-                    // var checkBox = groupLeft.appendChild(dom.createElement('input'))
-                    // checkBox.setAttribute('type', 'checkbox'); // @@ set from personal last settings
-                    var foo = function toggle(groupRow, group) {
-                        tabulator.panes.utils.deleteButtonWithCheck(dom, groupRow, "group", function(){
+                    var foo = function toggle(groupRow, group, name) {
+                        tabulator.panes.utils.deleteButtonWithCheck(dom, groupRow, "group " + name, function(){
                             deleteThing(group);
                         });
                         groupRow.addEventListener('click', function(event){
@@ -1220,12 +1257,6 @@ tabulator.panes.register( {
                             var groupList = kb.sym(group.uri.split('#')[0]);
                             if (!event.altKey) {
                                 selected = {}; // If alt key pressed, accumulate multiple
-                                /*
-                                cardMain.innerHTML = ''; 
-                                cardMain.appendChild(tabulator.panes.utils.ACLControlBox(group, dom, function(ok, body){
-                                    if (!ok) cardMain.innerHTML = "Failed: " + body;
-                                }));
-                                */
                             }
                             selected[group.uri] = selected[group.uri] ? false : true;
                             refreshGroups();
@@ -1244,7 +1275,7 @@ tabulator.panes.register( {
                             })
                         }, true);
                     };
-                    foo(groupRow, group);
+                    foo(groupRow, group, name);
                 }
                 
  
@@ -1311,7 +1342,7 @@ tabulator.panes.register( {
                     // cardMain.appendChild(newContactForm(dom, kb, selected, createdNewContactCallback1));
                     cardMain.appendChild(getNameForm(dom, kb, "Group", selected,
                         function(subject, name, selectedGroups) {
-                            createNewGroup(subject, name, function(success, body) {
+                            saveNewGroup(subject, name, function(success, body) {
                                 if (!success) {
                                      console.log("Error: can\'t save new group:" + body);
                                      cardMain.innerHTML = "Failed to save group" + body