docs: function setRule (rule, isDefault) {
      // clear id for existing rules
      this.id = undefined
      // if this is default rule then add to list
      if (isDefault) {
          this.defaultRules.push(_.cloneDeep(rule))
      }
      // capture original rule as string for error logging
      var origRule = rule.join(',')
      // require array
      assert.ok(Array.isArray(rule), 'rule array required')
      // get roles array
      var roles = rule
      // get rule string from last element in array
      rule = roles.pop()
      // require rule to be a string
      assert.ok(typeof rule === 'string', 'invalid rule '+origRule)
      // require at least one role
      assert.ok(roles.length, 'one or more roles required '+origRule)
      // split rule on colon to separate into clauses
      var ruleClauses = rule.split(':')
      // first clause must identify type of resource
      var resourceType = ruleClauses.shift()
      // get index of last element in rule
      var lastIdx = ruleClauses.length - 1
      // final element in rule must be 1 or 0 to indicate allow or deny
      var allow = parseInt(ruleClauses[lastIdx])
      // validate
      assert.ok(allow === 0 || allow === 1, 'allow must be 0 or 1 '+origRule)
      // set value to boolean
      ruleClauses[lastIdx] = allow
      // deny rule only allowed on all role
      if (allow === 0) {
          assert.ok(roles.length === 1 && roles[0] === 'all', 'deny can only be set for all role '+origRule)
      }
      // require valid resource type
      assert.ok(resourceTypes[resourceType], 'invalid resource type '+origRule)
      // create entry from resource type if it does not exist
      if (!this.rules[resourceType]) {
          this.rules[resourceType] = {}
      }
      // call type specific method to set rule
      resourceTypes[resourceType](roles, ruleClauses, this.rules[resourceType], origRule)
  }