 
     active-groups))
 
-(defn active-feature? [feature group-definition user]
+(defn active-feature?
+  "works out if a user is active in a feature, by checking percentages, if
+  they're specifically marked as active, or if they're in a group that is
+  active"
+  [feature group-definition user]
   (or
     (is-active-in-percentage feature user)
     (is-active-user? feature user)


;; imperative shell
(defprotocol ShoutoutStorage
  (read-from-storage [storage ^String feature-name])
  (write-to-storage [storage  ^String feature-name ^String serialized]))

(defn get-from-storage [storage feature-name]
  (parse-feature feature-name (read-from-storage storage feature-name)))

(defn with-storage [storage feature-name f]
  (let [feature (get-from-storage storage feature-name)]
    (write-to-storage storage feature-name (serialize-feature
                                             (f feature)))))

(defn activate [{storage :storage} feature-name]
  (with-storage
    #(assoc %
            :percentage
            100)))

(defn deactivate [{storage :storage} feature-name]
  (with-storage
    #(assoc %
            :percentage
            0)))

(defn activate-group [{storage :storage} feature-name group]
  (with-storage
    (fn [feature]
      (update-in feature
                :groups
                 #(conj % group)))))

(defn deactivate-group [{storage :storage} feature-name group]
  (with-storage
    (fn [feature]
      (update-in feature
                 :groups
                 #(disj % group)))))

(defn activate-user [{storage :storage} feature-name user]
  (with-storage
    (fn [feature]
      (update-in feature
                :users
                 #(conj % user)))))

(defn deactivate-user [{storage :storage} feature-name user]
  (with-storage
    (fn [feature]
      (update-in feature
                 :users
                 #(disj % user)))))

(defn activate-percentage [{storage :storage} feature-name percent]
  (with-storage
    (fn [feature]
      (assoc feature
             :percentage
             percent))))

(defn active? [{storage :storage groups :groups} feature-name user]
  (active-feature? (get-from-storage storage feature-name) groups user))

(defn shoutout [storage groups]
  {:storage storage
   :groups groups})

    0
    (Integer/parseInt raw)))

(defn parse-feature
  "turns a feature name and serialized feature into an feature"
  [^String feature-name ^String raw]
  (let [[raw-percentage raw-users raw-groups]
        (split raw #"\|")]
    (Feature. feature-name
