docs: function PolymerRedux(store) {
    if (!store) {
      throw new TypeError('PolymerRedux: expecting a redux store.');
    } else if (!['getState', 'dispatch', 'subscribe'].every(function (k) {
      return typeof store[k] === 'function';
    })) {
      throw new TypeError('PolymerRedux: invalid store object.');
    }
  
    var subscribers = new Map();
  
    /**
     * Binds element's properties to state changes from the Redux store.
     *
     * @example
     *     const update = bind(el, props) // set bindings
     *     update(state) // manual update
     *
     * @private
     * @param {HTMLElement} element
     * @param {Object} properties
     * @return {Function} Update function.
     */
    var bind = function bind(element, properties) {
      var bindings = Object.keys(properties).filter(function (name) {
        var property = properties[name];
        if (Object.prototype.hasOwnProperty.call(property, 'statePath')) {
          if (!property.readOnly && property.notify) {
            console.warn('PolymerRedux: <' + element.constructor.is + '>.' + name + ' has "notify" enabled, two-way bindings goes against Redux\'s paradigm');
          }
          return true;
        }
        return false;
      });
  
      /**
       * Updates an element's properties with the given state.
       *
       * @private
       * @param {Object} state
       */
      var update = function update(state) {
        var propertiesChanged = false;
        bindings.forEach(function (name) {
          // Perhaps .reduce() to a boolean?
          var statePath = properties[name].statePath;
  
          var value = typeof statePath === 'function' ? statePath.call(element, state) : (0, _path.get)(state, statePath);
  
          var changed = element._setPendingPropertyOrPath(name, value, true);
          propertiesChanged = propertiesChanged || changed;
        });
        if (propertiesChanged) {
          element._invalidateProperties();
        }
      };
  
      // Redux listener
      var unsubscribe = store.subscribe(function () {
        var detail = store.getState();
        update(detail);
  
        element.dispatchEvent(new window.CustomEvent('state-changed', { detail: detail }));
      });
  
      subscribers.set(element, unsubscribe);
  
      return update(store.getState());
    };
  
    /**
     * Unbinds an element from state changes in the Redux store.
     *
     * @private
     * @param {HTMLElement} element
     */
    var unbind = function unbind(element) {
      var off = subscribers.get(element);
      if (typeof off === 'function') {
        off();
      }
    };
  
    /**
     * Merges a property's object value using the defaults way.
     *
     * @private
     * @param {Object} what Initial prototype
     * @param {String} which Property to collect.
     * @return {Object} the collected values
     */
    var collect = function collect(what, which) {
      var res = {};
      while (what) {
        res = Object.assign({}, what[which], res); // Respect prototype priority
        what = Object.getPrototypeOf(what);
      }
      return res;
    };
  
    /**
     * ReduxMixin
     *
     * @example
     *     const ReduxMixin = PolymerRedux(store)
     *     class Foo extends ReduxMixin(Polymer.Element) { }
     *
     * @polymerMixinClass
     *
     * @param {Polymer.Element} parent The polymer parent element.
     * @return {Function} PolymerRedux mixed class.
     */
    return function (parent) {
      return function (_parent) {
        _inherits(ReduxMixin, _parent);
  
        function ReduxMixin() {
          _classCallCheck(this, ReduxMixin);
  
          // Collect the action creators first as property changes trigger
          // dispatches from observers, see #65, #66, #67
          var _this = _possibleConstructorReturn(this, (ReduxMixin.__proto__ || Object.getPrototypeOf(ReduxMixin)).call(this));
  
          var actions = collect(_this.constructor, 'actions');
          Object.defineProperty(_this, '_reduxActions', {
            configurable: true,
            value: actions
          });
          return _this;
        }
  
        _createClass(ReduxMixin, [{
          key: 'connectedCallback',
          value: function connectedCallback() {
            _get(ReduxMixin.prototype.__proto__ || Object.getPrototypeOf(ReduxMixin.prototype), 'connectedCallback', this).call(this);
            var properties = collect(this.constructor, 'properties');
            bind(this, properties);
          }
        }, {
          key: 'disconnectedCallback',
          value: function disconnectedCallback() {
            _get(ReduxMixin.prototype.__proto__ || Object.getPrototypeOf(ReduxMixin.prototype), 'disconnectedCallback', this).call(this);
            unbind(this);
          }
  
          /**
           * Dispatches an action to the Redux store.
           *
           * @example
           *     element.dispatch({ type: 'ACTION' })
           *
           * @example
           *     element.dispatch('actionCreator', 'foo', 'bar')
           *
           * @example
           *     element.dispatch((dispatch) => {
           *         dispatch({ type: 'MIDDLEWARE'})
           *     })
           *
           * @param  {...*} args
           * @return {Object} The action.
           */
  
        }, {
          key: 'dispatch',
          value: function dispatch() {
            var _this2 = this;
  
            for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
              args[_key] = arguments[_key];
            }
  
            var actions = this._reduxActions;
  
            // Action creator
            var action = args[0];
  
            if (typeof action === 'string') {
              if (typeof actions[action] !== 'function') {
                throw new TypeError('PolymerRedux: <' + this.constructor.is + '> invalid action creator "' + action + '"');
              }
              action = actions[action].apply(actions, _toConsumableArray(args.slice(1)));
            }
  
            // Proxy async dispatch
            if (typeof action === 'function') {
              var originalAction = action;
              action = function action() {
                for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
                  args[_key2] = arguments[_key2];
                }
  
                // Replace redux dispatch
                args.splice(0, 1, function () {
                  return _this2.dispatch.apply(_this2, arguments);
                });
                return originalAction.apply(undefined, args);
              };
  
              // Copy props from the original action to the proxy.
              // see https://github.com/tur-nr/polymer-redux/issues/98
              Object.keys(originalAction).forEach(function (prop) {
                action[prop] = originalAction[prop];
              });
            }
  
            return store.dispatch(action);
          }
  
          /**
           * Gets the current state in the Redux store.
           *
           * @return {*}
           */
  
        }, {
          key: 'getState',
          value: function getState() {
            return store.getState();
          }
        }]);
  
        return ReduxMixin;
      }(parent);
    };
  }