/**
 * Application object.
 *
 * @typedef {Object} app
 * @property {Object} [initial={}] - an object that represents the initial state.
 * If not specified, the initial state will be `{}`.
 * @property {Function} [Actions=()=>({})] - a function that creates actions, of the form
 * `update => actions`.
 * @property {Array<Function>} [services=[]] - an array of service functions, each of which
 * should be `({ state, previousState, patch }) => patch?`.
 * @property {Array<Function>} [effects=[]] - an array of effect functions, each of which
 * should be `({ state, previousState, patch, update, actions }) => void`, with the function
 * optionally calling `update` and/or `actions`.
 */

/**
 * Stream library. This works with `meiosis.simpleStream`, `flyd`, `m.stream`, or anything for
 * which you provide either a function or an object with a `stream` function to create a stream. The
 * function or object must also have a `scan` property. The returned stream must have a `map`
 * method.
 *
 * @typedef {Object|Function} StreamLib
 * @param {*} [value] - the stream's initial value.
 * @property {Function} stream - the function to create a stream, if the stream library itself is
 * not a function.
 * @property {Function} scan - the stream library's `scan` function.
 * @return {simpleStream} - the created stream.
 */

/**
 * Base helper to setup the Meiosis pattern. If you are using Mergerino, Function Patches, or Immer,
 * use their respective `setup` function instead.
 *
 * Patch is merged in to the state by default. Services have access to the state, previous state,
 * and patch, and can return a patch that further updates the state, reverts to the previous state,
 * and so on. State changes by services are available to the next services in the list.
 *
 * After the services have run and the state has been updated, effects are executed and have the
 * opportunity to trigger more updates.
 *
 * @async
 * @function meiosis.common.setup
 *
 * @param {StreamLib} stream - the stream library. This works with `meiosis.simpleStream`, `flyd`,
 * `m.stream`, or anything for which you provide either a function or an object with a `stream`
 * function to create a stream. The function or object must also have a `scan` property. The
 * returned stream must have a `map` method.
 * @param {Function} accumulator - the accumulator function.
 * @param {Function} combine - the function that combines an array of patches into one.
 * @param {app} app - the app, with optional properties.
 *
 * @returns {Object} - `{ update, states, actions }`, where `update` and `states` are streams, and
 * `actions` are the created actions.
 */
export default ({ stream, accumulator, combine, app }) => {
  if (!stream) {
    throw new Error("No stream library was specified.");
  }
  if (!accumulator) {
    throw new Error("No accumulator function was specified.");
  }
  if (!combine) {
    throw new Error("No combine function was specified.");
  }

  app = app || {};
  let { initial, Actions, services, effects } = app;
  initial = initial || {};
  services = services || [];
  effects = effects || [];

  const singlePatch = patch => (Array.isArray(patch) ? combine(patch) : patch);
  const accumulatorFn = (state, patch) => (patch ? accumulator(state, singlePatch(patch)) : state);

  const createStream = typeof stream === "function" ? stream : stream.stream;
  const scan = stream.scan;

  const update = createStream();
  const actions = (Actions || (() => ({})))(update);
  const states = createStream();

  // context is { state, patch, previousState }
  // state is optionally updated by service patches; patch and previousState never change.
  const runServices = context => {
    const updatedContext = context;

    for (let i = 0; i < services.length; i++) {
      // a service should (optionally) return a patch
      const servicePatch = services[i](updatedContext);
      updatedContext.state = accumulatorFn(updatedContext.state, servicePatch);
    }
    return updatedContext;
  };

  const contexts = scan(
    (context, patch) =>
      runServices({
        previousState: context.state,
        state: accumulatorFn(context.state, patch),
        patch
      }),
    runServices({ state: initial, previousState: {} }),
    update
  );

  contexts
    .map(context => {
      if (context.state !== states()) {
        states(context.state);
      }

      return Object.assign(context, {
        update,
        actions
      });
    })
    .map(context => {
      effects.forEach(effect => effect(context));
    });

  return { update, states, actions };
};

@@ -3428,16 +3428,49 @@
 ream();%0A
+  const states = createStream();%0A
   const 
@@ -3515,41 +3515,16 @@
 date
-);%0A  const states = createStream(
+, states
 );%0A%0A
@@ -3668,264 +3668,89 @@
 .%0A  
-const runServices = context =%3E %7B
+scan(
 %0A    
+(
 con
-st updatedContext = context;%0A%0A    for (let i = 0; i %3C services.length; i++) %7B%0A      // a service should (optionally) return a patch%0A      const servicePatch = services%5Bi%5D(updatedContext);%0A      updatedContext.
+text, patch) =%3E (%7B%0A      previousState: context.state,%0A      
 state
- =
+:
  acc
@@ -3760,24 +3760,17 @@
 latorFn(
-updatedC
+c
 ontext.s
@@ -3779,91 +3779,145 @@
 te, 
-serviceP
+patch),%0A      p
 atch
-);
 %0A    %7D
+),
 %0A    
-return updatedContext;%0A  %7D;%0A%0A  const 
+%7B state: initial, previousState: %7B%7D %7D,%0A    update%0A  )%0A    .map(
 context
-s
  =
- scan(%0A
+%3E%0A      services.reduce(%0A  
     
+  
 (con
@@ -3918,29 +3918,31 @@
   (context, 
-patch
+service
 ) =%3E%0A      r
@@ -3944,219 +3944,146 @@
     
-runServices(%7B%0A        previousState: context.state,%0A        state: accumulatorFn(context.state, patch),%0A        patch%0A      %7D),%0A    runServices(%7B state: initial, previousState: %7B%7D %7D),%0A    update%0A  );%0A%0A  contexts
+    Object.assign(context, %7B%0A            state: accumulatorFn(context.state, service(context))%0A          %7D),%0A        context%0A      )%0A    )
 %0A   

Update meiosis-setup