   class Lock
     postfix: '-better-bibtex-locked'
 
+    constructor: ->
+      @mark = { ts: new Date() }
+
     lock: Zotero.Promise.coroutine((msg)->
-      #@decks = {}
-      #for id in [ 'zotero-items-pane-content', 'zotero-item-pane-content' ]
-      #  @decks[id] = {
-      #    element: document.getElementById(id)
-      #    id: id
-      #  }
-      #  @decks[id].selected = @decks[id].element.selectedIndex
-      #  do (deck = @decks[id]) =>
-      #    @hide(deck.element)
-      #    deck.observer = new MutationObserver((mutations) => @hide(deck.element))
-      #    deck.observer.observe(deck.element, {attributes: true, childList: true})
-      #    return
-
       yield Zotero.uiReadyPromise
 
       yield Zotero.unlockPromise if Zotero.locked
 
-      Zotero.showZoteroPaneProgressMeter(msg || 'Initializing Better BibTeX...')
+      @update(msg || 'Initializing')
 
       @toggle(true)
 
       return
     )
 
+    bench: (msg) ->
+      ts = new Date()
+      debug('Lock:', @mark.msg, 'took', (ts - @mark.ts) / 1000.0, 's') if @mark.msg
+      @mark = { ts, msg }
+      return
+
     update: (msg) ->
-      Zotero.showZoteroPaneProgressMeter(msg)
+      @bench(msg)
+      Zotero.showZoteroPaneProgressMeter("Better BibTeX: #{msg}...")
       return
 
     unlock: ->
-      #return unless @decks
-
-      #for id, deck of @decks
-      #  deck.observer.disconnect()
-      #  deck.element.selectedIndex = deck.selected
-      #  deck.element.removeChild(document.getElementById(id + @postfix))
-      #@decks = null
+      @bench()
 
       Zotero.hideZoteroPaneOverlays()
-
       @toggle(false)
 
       return


    ready = Zotero.Promise.defer()
    module.exports.ready = ready.promise
    bench.start = new Date()

    # progressWin = new Zotero.ProgressWindow({ closeOnClick: false })

    # progressWin.changeHeadline('BetterBibTeX: Waiting for Zotero database')
    # progressWin.show()

    # oh FFS -- datadir is async now

    lock = new Lock()
    yield lock.lock('BetterBibTeX: Waiting for Zotero database...')

    CACHE.init()
    bench('Zotero.uiReadyPromise')

    # Zotero startup is a hot mess; https://groups.google.com/d/msg/zotero-dev/QYNGxqTSpaQ/uvGObVNlCgAJ
    yield Zotero.Schema.schemaUpdatePromise
    bench('Zotero.Schema.schemaUpdatePromise')

    # progressWin.changeHeadline('BetterBibTeX: Initializing')
    lock.update('BetterBibTeX: Initializing...')

    yield DB.init()
    bench('DB.init()')

    AutoExport.init()
    bench('AutoExport.init()')

    yield KeyManager.init() # inits the key cache by scanning the DB
    bench('KeyManager.init()')

    yield Serializer.init() # creates simplify et al
    bench('Serializer.init()')

    if Prefs.get('testing')
      module.exports.TestSupport = require('./test/support.coffee')
      bench('Zotero.BetterBibTeX.TestSupport')
    else
      debug('starting, skipping test support')

    JournalAbbrev.init()

    yield Translators.init()
    bench('Translators.init()')

    # progressWin.changeHeadline('BetterBibTeX: Ready for business')
    # progressWin.startCloseTimer(500)

    # should be safe to start tests at this point. I hate async.

    ready.resolve(true)
    bench('ready')

    lock.unlock()


          debug("event.#{type}.#{action}", {ids, extraData})
          KeyManager.remove(ids)
          events.emit('items-removed', ids)

        when 'add', 'modify'
          for item in items
