       when 'object'
         @set key, @get(key) ? defaultValue for own key, defaultValue of keys
       when 'string' then @set keys, @get(keys) ? defaultValue
+
+  # For each of the specified `keys`, retrieve their value in `localStorage`
+  # and pass it, along with the key, to the `callback` function provided.  
+  # If `callback` returns a value that is not `undefined`, then that value will
+  # be assigned to the key in `localStorage`. This functionality is very useful
+  # when just manipulating existing values but can be used in any case.
+  modify: (keys..., callback) ->
+    @set key, callback?(@get(key), key) ? @get key for key in keys
 
   # Remove the specified `keys` from `localStorage`.  
   # If only one key is specified then the current value of that key is returned

        localStorage[keys] = if value? then JSON.stringify value else value
        oldValue

  # For each of the specified `keys`, retrieve their value in `localStorage`
  # and pass it, along with the key, to the `callback` function provided.  
  # If `callback` returns a value that is not `undefined`, then that value will
  # be assigned to the key in `localStorage`. This functionality is very useful
  # when just manipulating existing values but can be used in any case.
  sync: (keys..., callback) ->
    @set key, callback?(@get(key), key) ? @get key for key in keys

  # Internationalization functions
  # ------------------------------

  # Convenient shorthand for `chrome.i18n.getMessage`.
  i18n: ->
    chrome.i18n.getMessage arguments...

  # Internationalize the specified attribute of all the selected elements.
  i18nAttribute: (selector, attribute, value, subs) ->
    elements = document.querySelectorAll selector
    # Ensure the substitution string(s) are in an array.
    subs = [subs] if typeof subs is 'string'
    for element in elements
      element.setAttribute attribute, @i18n value, subs

  # Internationalize the contents of all the selected elements.
  i18nContent: (selector, value, subs) ->
    elements = document.querySelectorAll selector
    # Ensure the substitution string(s) are in an array.
    subs = [subs] if typeof subs is 'string'
    element.innerHTML = @i18n value, subs for element in elements

  # Perform all internationalization setup required for the current page.
  i18nSetup: (subMap) ->
    i18nProcess document, subMap

  # Log functions
  # -------------

  # Output all failed `assertions`.
  assert: (assertions...) ->
    console.assert assertion for assertion in assertions if @logging()

  # Create/increment a counter and output its current count for all `names`.
  count: (names...) ->
    console.count name for name in names if @logging()

  # Output all debug `entries`.
  debug: (entries...) ->
    console.debug entry for entry in entries if @logging()

  # Display an interactive listing of the properties of all `entries`.
  dir: (entries...) ->
    console.dir entry for entry in entries if @logging()

  # Output all error `entries`.
  error: (entries...) ->
    console.error entry for entry in entries if @logging()

  # Output all informative `entries`.
  info: (entries...) ->
    console.info entry for entry in entries if @logging()

  # Output all general `entries`.
  log: (entries...) ->
    console.log entry for entry in entries if @logging()

  # Indicates whether or not logging is enabled.
  logging: ->
    @get 'log'

  # Start a timer for all `names`.
  time: (names...) ->
    console.time name for name in names if @logging()

  # Stop a timer and output its elapsed time in milliseconds for all `names`.
  timeEnd: (names...) ->
    console.timeEnd name for name in names if @logging()

  # Output a stack trace.
  trace: ->
    console.trace() if @logging()

  # Output all warning `entries`.
  warn: (entries...) ->
    console.warn entry for entry in entries if @logging()
          obj = element
          obj = obj[path.shift()] while obj and path.length > 1
          if obj
            obj[path] = i18n.get value, subs
            i18nProcess element, subMap if path is 'innerHTML'
        else
          element.setAttribute propName, i18n.get propExpr, subs
# List of internationalization attributes/handlers available.
i18nAttributes = []
i18nAttributes.push key for own key of i18nHandlers
