text: 'use strict';
  
  var Devices = module.exports;
  // TODO enumerate store's keys and device's keys for documentation
  Devices.addPort = function (store, serverport, newDevice) {
    // TODO make special
    return Devices.add(store, serverport, newDevice, true);
  };
  Devices.add = function (store, servername, newDevice, isPort) {
    if (isPort) {
      if (!store._ports) { store._ports = {}; }
    }
  
    // add domain (also handles ports at the moment)
    if (!store._domains) { store._domains = {}; }
    if (!store._domains[servername]) { store._domains[servername] = []; }
    store._domains[servername].push(newDevice);
    Devices.touch(store, servername);
  
    // add device
    // TODO only use a device id 
    var devId = newDevice.id || servername;
    if (!newDevice.__servername) {
      newDevice.__servername = servername;
    }
    if (!store._devices) { store._devices = {}; }
    if (!store._devices[devId]) {
      store._devices[devId] = newDevice;
      if (!store._devices[devId].domainsMap) { store._devices[devId].domainsMap = {}; }
      if (!store._devices[devId].domainsMap[servername]) { store._devices[devId].domainsMap[servername] = true; }
    }
  };
  Devices.alias = function (store, servername, alias) {
    if (!store._domains[servername]) {
      store._domains[servername] = [];
    }
    if (!store._domains[servername]._primary) {
      store._domains[servername]._primary = servername;
    }
    if (!store._domains[servername].aliases) {
      store._domains[servername].aliases = {};
    }
    store._domains[alias] = store._domains[servername];
    store._domains[servername].aliases[alias] = true;
  };
  Devices.remove = function (store, servername, device) {
    // Check if this domain has an active device
    var devices = store._domains[servername] || [];
    var index = devices.indexOf(device);
  
    if (index < 0) {
      console.warn('attempted to remove non-present device', device.deviceId, 'from', servername);
      return null;
    }
  
    // unlink this domain from this device
    var domainsMap = store._devices[devices[index].id || servername].domainsMap;
    delete domainsMap[servername];
    /*
    // remove device if no domains remain
    // nevermind, a device can hang around in limbo for a bit
    if (!Object.keys(domains).length) {
      delete store._devices[devices[index].id || servername];
    }
    */
  
    // unlink this device from this domain
    return devices.splice(index, 1)[0];
  };
  Devices.close = function (store, device) {
    var dev = store._devices[device.id || device.__servername];
    // because we're actually using names rather than  don't have reliable deviceIds yet
    if (!dev) {
      Object.keys(store._devices).some(function (key) {
        if (store._devices[key].socketId === device.socketId) {
          // TODO double check that all domains are removed
          delete store._devices[key];
          return true;
        }
      });
    }
  };
  Devices.bySocket = function (store, socketId) {
    var dev;
    Object.keys(store._devices).some(function (k) {
      if (store._devices[k].socketId === socketId) {
        dev = store._devices[k];
        return dev;
      }
    });
    return dev;
  };
  Devices.list = function (store, servername) {
    console.log('[dontkeepme] servername', servername);
    // efficient lookup first
    if (store._domains[servername] && store._domains[servername].length) {
      // aliases have ._primary which is the name of the original
      return store._domains[servername]._primary && store._domains[store._domains[servername]._primary] || store._domains[servername];
    }
    // There wasn't an exact match so check any of the wildcard domains, sorted longest
    // first so the one with the biggest natural match with be found first.
    var deviceList = [];
    Object.keys(store._domains).filter(function (pattern) {
      return pattern[0] === '*' && store._domains[pattern].length;
    }).sort(function (a, b) {
      return b.length - a.length;
    }).some(function (pattern) {
      var subPiece = pattern.slice(1);
      if (subPiece === servername.slice(-subPiece.length)) {
        console.log('[Devices.list] "'+servername+'" matches "'+pattern+'"');
        deviceList = store._domains[pattern];
  
        // Devices.alias(store, '*.example.com', 'sub.example.com'
        // '*.example.com' retrieves a reference to 'example.com'
        // and this reference then also referenced by 'sub.example.com'
        // Hence this O(n) check is replaced with the O(1) check above
        Devices.alias(store, pattern, servername);
        return true;
      }
    });
  
    return deviceList;
  };
  /*
  Devices.active = function (store, id) {
    var dev = store._devices[id];
    return !!dev;
  };
  */
  Devices.exist = function (store, servername) {
    if (Devices.list(store, servername).length) {
      Devices.touch(store, servername);
      return true;
    }
    return false;
  };
  Devices.next = function (store, servername) {
    var devices = Devices.list(store, servername);
    var device;
  
    if (devices._index >= devices.length) {
      devices._index = 0;
    }
    device = devices[devices._index || 0];
    devices._index = (devices._index || 0) + 1;
  
    if (device) { Devices.touch(store, servername); }
    return device;
  };
  Devices.touchDevice = function (store, device) {
    // TODO use device.id (which will be pubkey thumbprint) and store._devices[id].domainsMap
    Object.keys(device.domainsMap).forEach(function (servername) {
      Devices.touch(store, servername);
    });
  };
  Devices.touch = function (store, servername) {
    if (!store._recency) { store._recency = {}; }
    store._recency[servername] = Date.now();
  };
  Devices.lastSeen = function (store, servername) {
    if (!store._recency) { store._recency = {}; }
    return store._recency[servername] || 0;
  };
  