           model = @shortcuts.get collectionName, obj.name
           return  unless model
 
-          silent = if model.options?.custom then yes else no
-
-          # -------------------------------
-          # about custom shortcuts (eg ace)
-          # -------------------------------
-          #
-          # i don't really want to embed such logic into _shortcuts_; it should be
-          # totally 'shortcut type' agnostic and api provides the necessity to deal
-          # with such cases indeed.
-          #
-          # passing 'silent' as the 4th argument to shortcuts#update makes sure its
-          # internal keyconfig#change listener won't get dispatched anyhow, thus
-          # rendering the model in question unbound. plus, there is the _options_
-          # object you can use to denote such weirdos.
-          #
-          # just make sure you don't put any 'custom shortcut' set names
-          # into a bant.json file, since these sets are automatically thought to
-          # be _shortcuts_ compatible.
-
-          binding = null
-
-          if _.isArray obj.binding
-            binding = cloneArray model.binding
-            binding[osIndex] = [].concat(obj.binding).filter _.isString
-
           @emit 'change', collection,
-            shortcuts.update collectionName, obj.name,
-              binding: binding
-              options: options
-            , silent
-
-    # persist to app storage whenever a shortcut is changed.
-    # this should handled with some care to avoid exhausting
-    # resources, since _shortcuts_ emits all changes.
-    @shortcuts.on 'change', _.bind @_save, this
-
-
+            @shortcuts.update collectionName, model.name,
+              binding: klass._insertPlatformBinding model, obj.binding
+              options: obj.options
+            , klass._isCustomShortcut model
+
+    @shortcuts.on 'change', _.bind @_handleShortcutsChange, this
+
+
+  # Invalidates previous app's keyboard events and adds new
+  # listeners for the current one.
+  #
   _handleFrontAppChange: (app, prevApp) ->
-    # invalidates previous app's keyboard events and adds new
-    # listeners for the current one
 
     appId     = app.canonicalName
     prevAppId = prevApp?.canonicalName

      version : STORAGE_VERSION
      fetch   : no

    # make sure we are not accessing storage until its ready.
    # this also updates kb bindings which are initially listening
    # for default combos.
    @_store.once 'ready', _.bind @_handleStoreReady, this

    # add valid kb event listeners and invalidate obsolete upon
    # front application is set and ready
    appManager.on 'FrontAppChange', _.bind @_handleFrontAppChange, this

    @_store.fetchStorage null, yes


  _save: _.throttle (collection, model) ->

    throw 'could not persist changes'  unless @_store.isReady
    # also means: do not call this method explicitly, use #update

    throw 'not implemented :trollface:'

  , THROTTLE_WAIT,
    leading  : no
    trailing : yes


  _handleStoreReady: ->

    osIndex = if globals.os is 'mac' then 1 else 0

    @shortcuts.config.each (collection) =>
      collectionName = collection.name

        @shortcuts.on "key:#{key}", app.bound 'handleShortcut'


  # Renders a _kd#Modal_ immediately.
  #
  showModal: ->

    new ShortcutsModal {}, @shortcuts.config


  # Proxy to _shortcuts#get_.
  #
  # See: http://github.com/koding/shortcuts#api
  #
  get: ->

    @shortcuts.get.apply @shortcuts, Array::slice.call arguments

  # Updates a _keyconfig#Model_.
  #
  # This api is pretty-much same with _shortcuts#update_.
  #
  # One important difference is _silent_ argument is handled internally,
  # and not exposed. That's because passing _silent_ to _shortcuts#update_
  # as true makes sure _shortcuts_ doesn't add any keyboard event listeners,
  # yet it still updates the underlying _keyconfig_ instance.
  #
  # This is how we deal with shortcuts that should be handled manually.
  #
  update: (collectionName, modelName, value) ->

    throw 'value must be an object'  unless _.isObject value

    overrides = _.pick value, 'binding', 'options'

    unless Object.keys(overrides).length
      throw 'value should contain \'binding\' and/or \'options\' props'

    unless @_store.isReady
      console.warn 'changes won\'t be persisted, since storage is not ready yet'

    model = @shortcuts.get collectionName, modelName
    throw "#{modelName} not found"  unless model

    if overrides.binding
      overrides.binding = klass._insertPlatformBinding model, overrides.binding

    silent = klass._isCustomShortcut model

    res = @shortcuts.update collectionName, modelName, overrides, silent

    if silent then @_handleShortcutsChange @shortcuts.get(collectionName), res

    return res


  # Convenience method that returns a _keyconfig#Collection's_ json representation
  # for the current platform. Optionally takes a filter predicate.
  #
  getJSON: (name, predicate) ->

    set = @shortcuts.get(name)?.chain()

    if set
      if predicate then set = set.filter predicate

      set.map (model) ->
        _.extend model.toJSON(), binding: klass._getPlatformBinding model
      .value()


  # Returns the app storage key for the current platform.
  #
  # This will either be *shortcuts-mac* or *shortcuts-win*.
  #
  @getPlatformStorageKey: ->

    "#{STORAGE_NAME}-#{globals.keymapType}"


  # Returns _binding_ getter method name of a _keyconfig#Model_ for the current platform.
  #
  # This is memoized, so subsequent calls will return the cached result;
  # it still must be defined at static level since _globals_ must be ready.
  #
  # This will either be *getMacKeys* or *getWinKeys*.
  #
  # See: http://github.com/koding/keyconfig#api
  #
  @_bindingGetterMethodName: _.memoize ->

    kmt = globals.keymapType
    return "get#{kmt.charAt(0).toUpperCase()}#{kmt.slice 1, 3}Keys"


  # Given a _keyconfig#Model_, returns its binding for the current platform.
  #
  @_getPlatformBinding: (model) ->

    return model[klass._bindingGetterMethodName()]()


  # Returns _binding_ array index of a _keyconfig#Model_ for the current platform.
  #
  # This is memoized, so subsequent calls will return the cached result;
  # it still must be defined at static level since _globals_ must be ready.
  #
  # This will either be 1 for mac or 0 for windows/linux.
  #
  # See: http://github.com/koding/keyconfig#spec
  #
  @_bindingPlatformIndex: _.memoize ->

    if globals.keymapType is 'mac' then 1 else 0


  # Given a keyconfig#Model and a 1d array of bindings, validates and inserts
  # the array at the correct position for the current platform, and returns
  # a deep clone of the model's binding.
  #
  @_insertPlatformBinding: (model, platformBinding) ->

    binding = cloneArray model.binding

    if _.isArray platformBinding
      binding[klass._bindingPlatformIndex()] = platformBinding.filter _.isString

    return binding


  # Returns *true* if given _keyconfig#Model_ is a custom shortcut.
  #
  @_isCustomShortcut: (model) ->

    if model.options?.custom then yes else no
