     collection: "with recursive collectiontree (collection) as (values (?) union all select c.collectionID from collections c join collectiontree ct on c.parentCollectionID = ct.collection) select max(dateModified) from collectiontree ct join collectionItems ci on ct.collection = ci.collectionID join items i on ci.itemID = i.itemID"
 
   endpoints:
+    'icon.png':
+      supportedMethods: ["GET"]
+      init: (url, data, sendResponseCallback) ->
+        # don't use Zotero.File.getContentsFromURL as it forces the output to text/plain
+        req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance()
+        req.open('GET', "chrome://zotero/skin/#{url.query.name}", false)
+        req.responseType = 'arraybuffer'
+        req.send(null)
+
+        return sendResponseCallback(req.status, 'text/plain', "#{req.status}, #{if req.response then 'got' else 'no'} content") if req.status != 200 || !req.response
+
+        return sendResponseCallback(200, 'image/png', String.fromCharCode.apply(null, new Uint8Array(req.response)))
+
     index:
       supportedMethods: ["GET"]
       init: (url, data, sendResponseCallback) ->

          for collection in Zotero.getCollections()
            @collection(collection)

          for group in Zotero.Groups.getAll()
            @group(group)

          # TODO: add saved searches
          return)

        sendResponseCallback(200, "application/atom+xml", feed.serialize())

      supportedMethods: ["GET"]
      init: (url, data, sendResponseCallback) ->
        item = Zotero.Items.getByLibraryAndKey(url.query.library, url.query.key)
        body = Zotero.File.getBinaryContents(item.getFile())
        sendResponseCallback(200, item.attachmentMIMEType || 'application/pdf', body)
        return

    group:
      supportedMethods: ["GET"]
      init: (url, data, sendResponseCallback) ->
        if url.query.id == ''
          updated = Zotero.DB.valueQuery(Zotero.OPDS.sql.index)
          feed = new Zotero.OPDS.Feed("/opds/group?id=#{url.query.id}", 'Group Libraries', updated, ->
            for group in Zotero.Groups.getAll()
              @group(group)
            return)

        else
          group = Zotero.Groups.getByLibraryID(url.query.id)
          updated = Zotero.DB.valueQuery(Zotero.OPDS.sql.group, url.query.id)

          feed = new Zotero.OPDS.Feed("/opds/group?id=#{url.query.id}", "Group: #{group.name}", updated, ->
            for collection in group.getCollections() || []
              @collection(collection)

            for search in Zotero.Searches.getAll(url.query.id)
              @search(search)

            for item in (new Zotero.ItemGroup('group', group)).getItems() || []
              @item(item)

            return)

        sendResponseCallback(200, "application/atom+xml", feed.serialize())
        return
