{"action":"created","comment":{"url":"https://api.github.com/repos/zotero/translators/pulls/comments/33820811","id":33820811,"diff_hunk":"@@ -1,131 +1,899 @@\n+\n {\n-\t\"translatorID\": \"5278b20c-7c2c-4599-a785-12198ea648bf\",\n-\t\"label\": \"ARTstor\",\n-\t\"creator\": \"Sebastian Karcher\",\n-\t\"target\": \"^https?://library\\\\.artstor\\\\.org\",\n-\t\"minVersion\": \"3.1\",\n-\t\"maxVersion\": \"\",\n-\t\"priority\": 100,\n-\t\"inRepository\": true,\n-\t\"translatorType\": 4,\n-\t\"browserSupport\": \"gcs\",\n-\t\"lastUpdated\": \"2014-11-13 15:09:17\"\n+    \"translatorID\": \"5278b20c-7c2c-4599-a785-12198ea648bf\",\n+    \"label\": \"ARTstor\",\n+    \"creator\": \"John Justin, Charles Zeng\",\n+    \"target\": \"\\.artstor|\\.sscommons\\.org:?\\w*\\/(open)*library\",\n+    \"minVersion\": \"3.1\",\n+    \"maxVersion\": \"\",\n+    \"priority\": 100,\n+    \"inRepository\": true,\n+    \"translatorType\": 4,\n+    \"browserSupport\": \"gcs\",\n+    \"lastUpdated\": \"2015-07-01 18:45:45\"\n }\n \n /*\n-\t***** BEGIN LICENSE BLOCK *****\n-\t\n-\tARTstor Translator, Copyright © 2012 Sebastian Karcher\n-\tThis file is part of Zotero.\n-\t\n-\tZotero is free software: you can redistribute it and/or modify\n-\tit under the terms of the GNU Affero General Public License as published by\n-\tthe Free Software Foundation, either version 3 of the License, or\n-\t(at your option) any later version.\n-\t\n-\tZotero is distributed in the hope that it will be useful,\n-\tbut WITHOUT ANY WARRANTY; without even the implied warranty of\n-\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n-\tGNU Affero General Public License for more details.\n-\t\n-\tYou should have received a copy of the GNU Affero General Public License\n-\talong with Zotero.  If not, see <http://www.gnu.org/licenses/>.\n-\t\n-\t***** END LICENSE BLOCK *****\n+    This translator works for Artstor library sites (http://library.artstor.org) and\n+    Artstor Shared Shelf Commons (http://www.sscommons.org)\n+    ***** BEGIN LICENSE BLOCK *****\n+    \n+    Artstor Translator, Copyright © 2015 John Justin, Charles Zeng\n+    \n+    Zotero is free software: you can redistribute it and/or modify\n+    it under the terms of the GNU Affero General Public License as published by\n+    the Free Software Foundation, either version 3 of the License, or\n+    (at your option) any later version.\n+    \n+    Zotero is distributed in the hope that it will be useful,\n+    but WITHOUT ANY WARRANTY; without even the implied warranty of\n+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+    GNU Affero General Public License for more details.\n+    \n+    You should have received a copy of the GNU Affero General Public License\n+    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.\n+    \n+    ***** END LICENSE BLOCK *****\n */\n \n-function getData(doc, checkOnly) {\n-\tvar data = {},\n-\t\twidgets = doc.getElementsByClassName('MetaDataWidget'),\n-\t\ttopWidget = null, topZIndex;\n-\t\n-\t// Dtermine the top metadata window\n-\tfor (var i=0; i<widgets.length; i++) {\n-\t\t\n-\t\tvar zindex = doc.defaultView.getComputedStyle(widgets[i], null)\n-\t\t\t.getPropertyValue('z-index');\n-\t\tif (!zindex && zindex !== 0) continue;\n-\t\t\n-\t\tif (!topWidget || topZIndex < zindex) {\n-\t\t\ttopWidget = widgets[i];\n-\t\t\ttopZIndex = zindex;\n-\t\t}\n-\t}\n-\t\n-\tif (!topWidget) return false;\n-\t\n-\tvar fields = topWidget.getElementsByClassName('field'),\n-\t\tfound = false;\n-\tfor (var i=0; i<fields.length; i++) {\n-\t\tvar field = ZU.trimInternal(fields[i].textContent);\n-\t\t\n-\t\tvar value = fields[i].nextElementSibling;\n-\t\tif (!value || !value.classList.contains('data')) continue;\n-\t\tvalue = ZU.unescapeHTML(ZU.cleanTags(value.innerHTML));\n-\t\t\n-\t\tif (!field || !value.trim()) continue;\n-\t\t\n-\t\tif (checkOnly) return true;\n-\t\t\n-\t\tfound = true;\n-\t\tdata[field] = value;\n-\t}\n-\t\n-\treturn found ? data : false;\n+/**\n+    detectWeb is run to determine whether item metadata can indeed be retrieved from the webpage. \n+    The return value of this function should be the detected item type (e.g. “journalArticle”, \n+    see the overview of Zotero item types), or, if multiple items are found, “multiple”. \n+**/\n+function detectWeb(doc, url) {\n+    if (url.match(/\\/iv2/)) {\n+        // Image viewer window\n+        return \"artwork\";\n+    } else if (url.match(/\\#3\\|/)) {\n+        // Thumbnail window page\n+        if ((doc.getElementsByClassName('MetaDataWidgetRoot') != null) && (doc.getElementsByClassName('MetaDataWidgetRoot').length > 0)) {\n+            // There are multiple metadata windows visible\n+            return \"artwork\";\n+        } else if ((doc.getElementById(\"floatingPlaceHolder\") != null) && (doc.getElementById(\"floatingPlaceHolder\").style.display == \"block\")) {\n+            // Don't capture date if small window is present\n+            return false;\n+        } else if ((doc.getElementById(\"thumbNavSave1\") != null) && (doc.getElementById(\"thumbNavSave1\").style.display == \"block\")) {\n+            // Don't capture data if image group window is in editing state.\n+            return false;\n+        } else if ((doc.getElementById(\"ssContentWrap\") != null) && (doc.getElementById(\"ssContentWrap\").style.display == \"inline\")) {\n+            // Don't capture data if slide show window is present\n+            return false;\n+        } else {\n+            if (url.match(/zMode/)) {\n+                return \"artwork\";\n+            }\n+        }\n+        // Allow thumbnail window.\n+        return \"multiple\";\n+    }\n+    // all other page, data can not be captured.\n+    return false;\n }\n \n-function detectWeb(doc, url) {\n-\t//monitor changes to body's direct children. That's where the metadata popup is added\n-\tZotero.monitorDOMChanges(doc.body, {childList: true});\n+/**\n+    Overall logic:\n+    - Detect the page context:\n+        - check if the page is main window (ignore)\n+        - check if the page is collection splash (ignore)\n+        - check if the page is thumbnail page\n+            - ignore small window\n+            - if small windows is popped up, process only small window\n+                get the object ids from small windows, then process the ids.\n+            - if no small window, get the selected object and process them\n+                get the object ids from selected objects, then process the ids.\n+            - otherwise, select all objects in the thumbnails\n+                get the object ids from the thumbnail windows, then process the ids.\n+        - check if the page is image viewer\n+            - get the object from the image viewer, then process the id.\n+    - Process the id\n+        - find the object type.\n+        - get the metadta service url from id using service call  http://library.artstor.org/library/secure/metadata/id\n+            - fetch and convert the metadata from the metadata service call\n+                - take into consideration of different metadata field for the portals\n+                - may need to convert/format the data values.\n+            - fetch the item notes using: \n+        - get the resource link url from id: :http://library.artstor.org/library/secure/metadata/id?_method=FpHtml\n+            - fetch the resource from resource url\n+            - set the item title and item mine type.\n \n-\tif (getData(doc, true)) {\n-\t\treturn \"artwork\";\n-\t}\n+    doWeb is run when a user, wishing to save one or more items, activates the selected translator. \n+    Sidestepping the retrieval of item metadata, we'll first focus on how doWeb can be used to save \n+    retrieved item metadata (as well as attachments and notes) to your Zotero library.**/\n+function doWeb(doc, url) {\n+    if (url.match(/\\/iv2/)) {\n+        doImageViewer(doc, url);\n+    }\n+    if (url.match(/#3\\|/)) {\n+        // Thumbnail window page\n+        if ((doc.getElementsByClassName('MetaDataWidgetRoot') != null) && (doc.getElementsByClassName('MetaDataWidgetRoot').length > 0)) {\n+            doMetadataWindow(doc, url);\n+        } else {\n+            var skipThumbnail = false;\n+            if ((doc.getElementById(\"floatingPlaceHolder\") != null) && (doc.getElementById(\"floatingPlaceHolder\").style.display == \"block\")) {\n+                // Don't capture date if small window is present\n+                skipThumbnail = true;\n+            }\n+            if ((doc.getElementById(\"thumbNavSave1\") != null) && (doc.getElementById(\"thumbNavSave1\").style.display == \"block\")) {\n+                // Don't capture data if image group window is in editing state.\n+                skipThumbnail = true;\n+            }\n+            if ((doc.getElementById(\"ssContentWrap\") != null) && (doc.getElementById(\"ssContentWrap\").style.display == \"inline\")) {\n+                // Don't capture data if slide show window is present\n+                skipThumbnail = true;\n+            }\n+            // Allow thumbnail window.\n+            if (!skipThumbnail) {\n+                doThumbnails(doc, url);\n+            }\n+        }\n+    }\n }\n \n-function associateData(newItem, value, field) {\n-\tif (!value) return;\n-\tif (typeof value == 'string') value = ZU.trimInternal(value);\n-\tif (!value) return;\n-\t\n-\tnewItem[field] = value;\n+function doImageViewer(doc, url) {\n+    // get the image id and object type from the page\n+    // this contains the objId and object type separate by : as in \"AWSS35953_35953_25701160:11\"\n+    var objID = doc.getElementById(\"objID\");\n+    if (objID != null) {\n+        var objItems = [];\n+        var objItem = doc.getElementById(\"objID\").title;\n+        objItems.push(objItem);\n+        processObjects(doc, url, objItems);\n+    }\n }\n \n-function doWeb(doc, url) {\n-\tvar newItem = new Zotero.Item(\"artwork\"),\n-\t\tdata = getData(doc),\n-\t\tcontent;\n-\t\n-\tif (data.Creator) {\n-\t\tcontent = data.Creator.replace(/\\s*\\(.*/, '');\n-\t\tassociateData(newItem,\n-\t\t\tZU.cleanAuthor(content, \"artist\", artist.indexOf(',') != -1),\n-\t\t\t'creators'\n-\t\t);\n-\t}\n-\t\n-\tif (data.Date) {\n-\t\tcontent = data.Date.replace(/^Photographed (?:in )?/, '');\n-\t\tassociateData(newItem, content, \"date\");\n-\t}\n-\t\n-\tif (data.Rights) {\n-\t\tvar m = data.Rights.match(/^.*(©.*)$/m);\n-\t\tif (m) associateData(newItem, m[1], \"rights\");\n-\t}\n-\t\n-\tif (data.Subject) {\n-\t\tcontent = data.Subject.split(/\\s*;\\s*/);\n-\t\tassociateData(newItem, content, 'tags');\n-\t}\n-\t\n-   //these might not be complete - it's pretty straightforward to add more\n-\tassociateData(newItem, data.Title, \"title\");\n-\tassociateData(newItem, data.Measurements, \"artworkSize\");\n-\tassociateData(newItem, data.Material, \"artworkMedium\");\n-\tassociateData(newItem, data.Repository, \"archive\");\n-\tassociateData(newItem, data['ID Number'], \"archiveLocation\");\n-\tassociateData(newItem, data.Description, \"abstractNote\");\n-\t\n-\tnewItem.complete();\n-}\n\\ No newline at end of file\n+function doMetadataWindow(doc, url) {\n+    // get object id from metadata window.\n+    var metaWindows = doc.getElementsByClassName('MetaDataWidgetRoot');\n+    var objItems = [];\n+    for (var i = 0; i < metaWindows.length; i++) {\n+        var id = metaWindows[i].id.substring(3);\n+        objItems.push(id);\n+    }\n+\n+    processSelectedObject(doc, url, objItems, 1);\n+}\n+\n+function processSelectedObject(doc, url, selectedObjs, selectionType) {\n+    var serviceURL = getThumbnailServiceURL(doc, url);\n+    Zotero.Utilities.HTTP.doGet(serviceURL, function(text) {\n+        // get the master object list\n+        var json = JSON.parse(text);\n+        var objDescItem;\n+        var masterObjList = [];\n+        for (var i = 0; i < json.thumbnails.length; i++) {\n+            var thumbnail = json.thumbnails[i];\n+            objDescItem = new Object();\n+            objDescItem.id = thumbnail.objectId;\n+            objDescItem.type = thumbnail.objectTypeId;\n+            objDescItem.title = thumbnail.thumbnail1;\n+            masterObjList.push(objDescItem);\n+        }\n+        // Proccess the selected items by look up the data from master list.\n+        var zMode = false;\n+        if (url.match(/zMode/)) {\n+            zMode = true;\n+        }\n+        switch (selectionType) {\n+            case 2: // selection from thumbnals\n+                var candidateItems = new Object();\n+                var masterObj;\n+                if (selectedObjs.length > 0) {\n+                    for (var j = 0; j < selectedObjs.length; j++) {\n+                        var idx = selectedObjs[j];\n+                        masterObj = masterObjList[idx];\n+                        var key = masterObj.id + \":\" + masterObj.type;\n+                        candidateItems[key] = masterObj.title;\n+                    }\n+                } else {\n+                    for (var j = 0; j < masterObjList.length; j++) {\n+                        masterObj = masterObjList[j];\n+                        var key = masterObj.id + \":\" + masterObj.type;\n+                        candidateItems[key] = masterObj.title;\n+                    }\n+                }\n+                if (zMode && Object.keys(candidateItems).length > 0) {\n+                    var objItems = [];\n+                    for (var objItem in candidateItems) {\n+                        objItems.push(objItem);\n+                        processObjects(doc, url, objItems);\n+                        break;\n+                    }\n+                } else {\n+                    Zotero.selectItems(candidateItems, function(selectItems) {\n+                        var objItems = [];\n+                        for (var objItem in selectItems) {\n+                            objItems.push(objItem);\n+                        }\n+                        processObjects(doc, url, objItems);\n+                    });\n+                }\n+                break;\n+            case 1: // item from metadata window or image viewer\n+                // build look up table for eazy look up.\n+                var masterLookup = new Object();\n+                for (var m = 0; m < masterObjList.length; m++) {\n+                    masterLookup[masterObjList[m].id] = masterObjList[m];\n+                }\n+                var objItems = [];\n+                for (var i = 0; i < selectedObjs.length; i++) {\n+                    var id = selectedObjs[i];\n+                    if (masterLookup[id] == \"\") {\n+                        var item = id + \":10\"; // default type as image.\n+                        objItems.push(item);\n+                    } else {\n+                        var item = masterLookup[id].id + \":\" + masterLookup[id].type;\n+                        objItems.push(item);\n+                    }\n+                }\n+                processObjects(doc, url, objItems);\n+                break;\n+        }\n+    }); // Zotero..doGet\n+};\n+\n+\n+function doThumbnails(doc, url) {\n+    var selectedObjs = getSelectedItems(doc, url);\n+    processSelectedObject(doc, url, selectedObjs, 2);\n+}\n+\n+/**\n+    getMasterThumbnailList gets the thumbnail object id by calling the thumbnail \n+    service to get a list of object id and its title.\n+    It returns with a list of object with object id, and object title.\n+**/\n+function getMasterThumbnailList(doc, url, objDescItems) {\n+    // var objDescItems = [];\n+    var serviceURL = getThumbnailServiceURL(doc, url);\n+    Zotero.Utilities.HTTP.doGet(serviceURL, function(text) {\n+        var json = JSON.parse(text);\n+        var objDescItem;\n+        for (var i = 0; i < json.thumbnails.length; i++) {\n+            var thumbnail = json.thumbnails[i];\n+            objDescItem = new Object();\n+            objDescItem.id = thumbnail.objectId;\n+            objDescItem.type = thumbnail.objectTypeId;\n+            objDescItem.title = thumbnail.thumbnail1;\n+            objDescItems.push(objDescItem);\n+        }\n+    });\n+    return objDescItems;\n+}\n+\n+/**\n+    getSelectedItems gets the selected item by checking the items selected.\n+    It returns with a list of object with index id.\n+**/\n+function getSelectedItems(doc, url) {\n+    var indexes = [];\n+    var wrap = doc.getElementById(\"thumbContentWrap\");\n+    if ((wrap !== null) && (wrap.style.display == \"none\")) {\n+        wrap = doc.getElementById(\"listContentWrap\");\n+    }\n+    if (wrap != null) {\n+        var imageElems = wrap.getElementsByClassName(\"thumbNailImageSelected\");\n+        for (var i = 0; i < imageElems.length; i++) {\n+            if (imageElems[i].parentNode.parentNode.style.display == \"block\") {\n+                var id = imageElems[i].id; // we need to get the index (1) from id string \"custom1_imageHolder\"\n+                var imageNum = id.substring(id.indexOf(\"m\") + 1, id.indexOf(\"_\"));\n+                indexes.push(parseInt(imageNum));\n+            }\n+        }\n+    }\n+    return indexes;\n+}\n+\n+/**\n+    processObjects gets the object data using service call.\n+    objIds has the following member: id, type\n+**/\n+function processObjects(doc, url, objIds) {\n+    for (var i = 0; i < objIds.length; i++) {\n+        var objItem = objIds[i];\n+        var dataItem = new Zotero.Item('artwork');\n+        dataItem.attachments.push({\n+            title: \"Artstor Thumbnails\",\n+            document: doc\n+        });\n+\n+        getMetaDataItem(url, objItem, dataItem);\n+    }\n+}\n+\n+function getMetaDataItem(url, objItem, dataItem) {\n+    var portalMap = {\n+        'flexspace': {\n+            'Campus': 'title',\n+            'Square Footage': 'artworkSize',\n+            'General Description': 'abstractNote',\n+            'Comments (Technology Integration)': 'abstractNote',\n+            'Rights': 'rights'\n+        },\n+        'archaeology': {\n+            'Site Name': 'title',\n+            'Artifact Title': 'title',\n+            'Artifact Description': 'abstractNote',\n+            'Artifact Repository': 'archive',\n+            'Rights': 'rights',\n+            'Site Date': 'date',\n+            'Artifact Materials/Techniques': 'artworkMedium',\n+            'Artifact Dimensions': 'artworkSize'\n+        },\n+        'default': {\n+            'Creator': 'creators',\n+            'Title': 'title',\n+            'Date': 'date',\n+            'Material': 'artworkMedium',\n+            'Measurements': 'artworkSize',\n+            'Repository': 'archive',\n+            'Rights': 'rights',\n+            'Description': 'abstractNote',\n+            'Accession Number': 'callNumber'\n+        }\n+    };\n+\n+    var itemAry = objItem.split(':');\n+    var serviceUrl = getServiceUrlRoot(url) + \"metadata/\" + itemAry[0];\n+    Zotero.Utilities.HTTP.doGet(serviceUrl, function(text) {\n+        var json = JSON.parse(text);\n+        var portal = getPortal(url);\n+        if (!(portal in portalMap)) {\n+            portal = 'default';\n+        }\n+        processPortalData(dataItem, json, portalMap[portal], portal);\n+        getNotesDataItem(url, objItem, dataItem);\n+    });\n+\n+    return dataItem;\n+}\n+\n+function processPortalData(dataItem, json, fieldMap, portal) {\n+    var fieldName;\n+    var fieldValue;\n+    if (portal == 'archaeology') {\n+        var hasSiteName = false;\n+        for (var i = 0; i < json.metaData.length; i++) {\n+            fieldName = json.metaData[i].fieldName;\n+            fieldValue = json.metaData[i].fieldValue;\n+            if (fieldName in fieldMap) {\n+                var key = fieldMap[fieldName];\n+                if (fieldName == 'Site Name') {\n+                    hasSiteName = true;\n+                    setItemValue(dataItem, \"title\", fieldValue);\n+                } else if (fieldName == 'Artifact Title') {\n+                    if (hasSiteName) {\n+                        setItemLabelValue(dataItem, \"extra\", fieldName, dataItem.title);\n+                        hasSiteName = false;\n+                    }\n+                    setItemValue(dataItem, \"title\", fieldValue);\n+                }\n+            } else {\n+                setItemLabelValue(dataItem, \"extra\", fieldName, fieldValue);\n+            }\n+        }\n+\n+    } else {\n+        for (var i = 0; i < json.metaData.length; i++) {\n+            fieldName = json.metaData[i].fieldName;\n+            fieldValue = json.metaData[i].fieldValue;\n+            if (fieldName in fieldMap) {\n+                var key = fieldMap[fieldName];\n+                if (key == 'creators') {\n+                    setItemCreator(dataItem, fieldValue);\n+                } else {\n+                    setItemValue(dataItem, key, fieldValue);\n+                }\n+            } else {\n+                setItemLabelValue(dataItem, \"extra\", fieldName, fieldValue);\n+            }\n+        }\n+    }\n+    if (dataItem.title == undefined) {\n+        dataItem.title = \"Unknown\";\n+    }\n+}\n+\n+function setItemCreator(dataItem, fieldValue) {\n+    fieldValue = fieldValue.replace(/<wbr\\/>/g, \"\");\n+    var names = [];\n+    if (fieldValue.indexOf(';')) {\n+        names = fieldValue.split(';')\n+    } else {\n+        names.push(fieldValue);\n+    }\n+    for (var i = 0; i < names.length; i++) {\n+        var str = names[i];\n+        var contributor = \"author\";\n+        var name = str;\n+\n+        if (str.indexOf(':') > 0) {\n+            var params = str.split(':');\n+            contributor = params[0];\n+            name = params[1];\n+        }\n+        dataItem.creators.push(ZU.cleanAuthor(name.replace(/<\\/?[^>]+(>|$)/g, \" \").replace(/(&gt;)|(&lt;)/g, \"\"), contributor, false));\n+    }\n+}\n+\n+function setItemLabelValue(dataItem, key, label, value) {\n+    var cleanValue = value.replace(/<\\/?[^>]+(>|$)/g, \" \");\n+    cleanValue = cleanValue.replace(/\\./, \"\");\n+    cleanValue = cleanValue.replace(/<wbr\\/>/g, \"\");\n+\n+    if (!(key in dataItem)) {\n+        dataItem[key] = label + \": \" + cleanValue;\n+\n+    } else {\n+        var fieldValue = dataItem[key];\n+        if (fieldValue.indexOf(label) >= 0) {\n+            dataItem[key] += \", \" + cleanValue;\n+        } else {\n+            dataItem[key] += \"; \" + label + \": \" + cleanValue;\n+\n+        }\n+    }\n+}\n+\n+function setItemValue(dataItem, key, value, override) {\n+    var cleanValue = value.replace(/<\\/?[^>]+(>|$)/g, \" \");\n+    cleanValue = cleanValue.replace(/\\./, \"\");\n+    cleanValue = cleanValue.replace(/<wbr\\/>/g, \"\");\n+\n+    if (!(key in dataItem) || override) {\n+        dataItem[key] = cleanValue;\n+\n+    } else {\n+        dataItem[key] += \"; \" + cleanValue;\n+    }\n+}\n+\n+function getNotesDataItem(url, objItem, dataItem) {\n+    var itemAry = objItem.split(':');\n+    var objType = itemAry[1];\n+    var serviceURL = getServiceUrlRoot(url) + \"icommentary/\" + itemAry[0];\n+    Zotero.Utilities.HTTP.doGet(serviceURL,\n+        function(text) {\n+            var json = JSON.parse(text);\n+            for (var j = 0; j < json.numberOfCommentaries; j = j + 1) {\n+                if (json.ICommentary[j].status == 2) {\n+                    //public commentary\n+                    var comment = \"\";\n+                    if (json.ICommentary[j].ownerName == \"\") {\n+                        comment = \"Note: \";\n+                    } else {\n+                        comment = \"Note by: \" + json.ICommentary[j].ownerName + \" -  \";\n+                    }\n+                    comment += json.ICommentary[j].commentary;\n+                    dataItem.notes.push({\n+                        note: comment\n+                    });\n+                }\n+            }\n+            getResourceDataItem(url, objItem, dataItem);\n+        }\n+    ); //doGet\n+\n+}\n+\n+\n+function getResourceDataItem(url, objItem, dataItem) {\n+    var itemAry = objItem.split(':');\n+    var serviceURL = getServiceUrlRoot(url) + \"metadata/\" + itemAry[0] + \"/\" + \"?_method=FpHtml\";\n+\n+    Zotero.Utilities.HTTP.doGet(serviceURL, function(text) {\n+        var service = text.substring(text.indexOf(\"secure\"));\n+        service = service.substring(0, service.indexOf(\"</td>\")).replace(/<wbr\\/>/g, \"\").substring(service.indexOf(\"?\")).trim();\n+        dataItem.url = getServerUrl(url) + \"secure/ViewImages\" + service + \"&zoomparams=&fs=true\";\n+        getNonImageDataItem(url, objItem, dataItem);\n+    });\n+}\n+\n+function getNonImageDataItem(url, objItem, dataItem) {\n+    var ARTSTOR_MEDIA_MAPPINGS = {\n+        \"11\": [\"7\", \"Artstor QuickTime Movie Attachment\", \"video/quicktime\"], //qtvr\n+        \"12\": [\"10\", \"Artstor Audio File Attachment\", \"audio/mpeg3\"], // audio\n+        \"20\": [\"20\", \"Artstor PDF Attachment\", \"application/pdf\"], // pdf\n+        \"21\": [\"21\", \"Artstor PowerPoint Attachment\", \"application/powerpoint\"], // powerpoint\n+        \"22\": [\"22\", \"Artstor Word Attachment\", \"application/msword\"], // word\n+        \"23\": [\"23\", \"Artstor Excel Attachment\", \"application/excel\"], // excel\n+        \"24\": [\"24\", \"Artstor Video File Attachment\", \"text/html\"], // video\n+    };\n+\n+    var itemAry = objItem.split(':');\n+    var objType = itemAry[1];\n+    var mediaInfo = ARTSTOR_MEDIA_MAPPINGS[objType];\n+    if (mediaInfo !== undefined) {\n+        var serviceURL = getServiceUrlRoot(url) + \"imagefpx/\" + itemAry[0] + \"/\" + mediaInfo[0];\n+\n+        Zotero.Utilities.HTTP.doGet(serviceURL, function(text) {\n+\n+            var json = JSON.parse(text);\n+            var imageUrl = json.imageUrl;\n+            var mediaUrl;\n+            if (imageUrl.indexOf('http') >= 0) {\n+                mediaUrl = json.imageUrl;\n+            } else {\n+                if (imageUrl.indexOf('/') == 0) {\n+                    mediaUrl = getFileRoot(url) + \"/thumb\" + imageUrl;\n+                } else {\n+                    mediaUrl = getFileRoot(url) + \"/thumb/\" + imageUrl;\n+                }\n+            }\n+            dataItem.attachments.push({\n+                title: mediaInfo[1],\n+                url: mediaUrl,\n+                mimeType: mediaInfo[2]\n+            });\n+            dataItem.url = url;\n+            dataItem.complete();\n+        });\n+    } else {\n+        dataItem.complete();\n+    }\n+    Zotero.done();\n+}\n+\n+function getPortal(url) {\n+    var portal = url.substring(7, url.indexOf(\".\"));\n+    return portal;\n+}\n+\n+function getServerUrl(url) {\n+    var serverUrl;\n+    if (url.indexOf('/iv2') > 0) {\n+        serverUrl = url.substring(0, url.indexOf('iv2\\.'));\n+    } else {\n+        serverUrl = url.substring(0, url.indexOf('#3'));\n+    }\n+    serverUrl = serverUrl.substring(0, serverUrl.lastIndexOf('/'));\n+    return serverUrl;\n+}\n+\n+function getThumbnailServiceURL(doc, url) {\n+    var serverUrl = getServerUrl(url);\n+    var paramStr = url.substring(url.indexOf('#'));\n+\n+    // process escapde \"|\"\n+    if (paramStr.indexOf('|') < 0) {\n+        paramStr = parramStr.replace(/%7c/gi, \"|\");\n+    }\n+\n+    var params = paramStr.split('|');\n+    var pageType = params[1];\n+    var contentId = params[2];\n+\n+    // get page number\n+    var pageNo = 0;\n+    var pageNoDOM = doc.getElementById(\"pageNo\");\n+    if (pageNoDOM != null) {\n+        pageNo = parseInt(pageNoDOM.value);\n+    }\n+\n+    // get page size\n+    var imagesPerPage = \"1\";\n+    var pageDOM = doc.getElementById(\"thumbNavImageButt\");\n+    if (pageDOM != null)\n+        imagesPerPage = pageDOM.innerHTML;\n+    var pageSize = parseInt(imagesPerPage);\n+    var startIdx = (pageNo - 1) * pageSize + 1;\n+\n+    // get sort order\n+    var sortOrder = 0; //scrape from page\n+    var sortUL = doc.getElementById(\"sub0sortList\");\n+    if (sortUL !== null) {\n+        var sortElemWChk = sortUL.getElementsByClassName('sortListItemNav');\n+        if ((sortElemWChk != null) && (sortElemWChk.length > 0)) {\n+            switch (sortElemWChk[0].id) {\n+                case \"thumbSortRelevance0\":\n+                    sortOrder = 0;\n+                    break;\n+                case \"thumbSortTitle0\":\n+                    sortOrder = 1;\n+                    break;\n+                case \"thumbSortCreator0\":\n+                    sortOrder = 2;\n+                    break;\n+                case \"thumbSortDate0\":\n+                    sortOrder = 3;\n+                    break;\n+            }\n+        }\n+    }\n+\n+    var serviceURL = \"\";\n+    switch (pageType) {\n+        case \"search\":\n+            var searchTerm = decodeSearchData(decrypt(params[7]));\n+\n+            var kw = searchTerm.kw;\n+            kw = encrypt(kw);\n+            var type = searchTerm.type;\n+\n+            var origKW = searchTerm.origKW;\n+            origKW = escape(origKW);\n+            var order = 0;\n+            if (type == \"3\" || type == \"2\") {\n+                //search within IG and categories\n+                serviceURL = getServiceUrlRoot(url) + pageType + \"/\" + params[2] + \"/\" + startIdx + \"/\" + pageSize + \"/\" + sortOrder + \"?type=\" + type + \"&kw=\" +\n+                    kw + \"&origKW=\" + origKW + \"&id=\" + searchTerm.id + \"&name=\" + escape(searchTerm.name); + \"&order=\" + order + \"&tn=1\";\n+\n+            } else if (type == \"4\") {\n+                //search notes\n+                var aType = searchTerm.aType;\n+                serviceURL = getServiceUrlRoot(url) + pageType + \"/\" + params[2] + \"/\" + startIdx + \"/\" + pageSize + \"/\" + sortOrder + \"?type=\" + type + \"&kw=\" +\n+                    kw + \"&origKW=\" + origKW + \"&aType=\" + aType + \"&order=\" + order + \"&tn=1\";\n+\n+            } else {\n+                //KW search type=6, PC, All Coll, Inst Coll, Adv Srch\n+                var collectionTit = decrypt(params[3]);\n+                var collectionTitle = collectionTit.split(\":\");\n+                var name = escape(collectionTitle[0]);\n+                serviceURL = getServiceUrlRoot(url) + pageType + \"/\" + params[2] + \"/\" + startIdx + \"/\" + pageSize + \"/\" + sortOrder + \"?type=\" + type + \"&kw=\" +\n+                    kw + \"&origKW=\" + origKW + \"&geoIds=\" + searchTerm.geoIds + \"&clsIds=\" + searchTerm.clsIds + \"&collTypes=\" + searchTerm.collTypes + \"&id=\" +\n+                    searchTerm.id + \"&name=\" + name + \"&bDate=\" + searchTerm.bDate +\n+                    \"&eDate=\" + searchTerm.eDate + \"&dExact=\" + searchTerm.dExact + \"&order=\" + order + \"&isHistory=false&prGeoId=\" + searchTerm.prGeoId + \"&tn=1\";\n+            }\n+            //p=escape(p);\n+            break;\n+        case \"collaboratoryfiltering\":\n+            var serviceURL = getServiceUrlRoot(url) + pageType + \"/\" + params[2] + \"/thumbnails/\" + startIdx + \"/\" + pageSize + \"/\" + sortOrder + \"?collectionId=\" + params[8];\n+            break;\n+        case \"imagegroup\": // image group\n+        case \"collections\":\n+        case \"categories\":\n+        case \"cluster\":\n+        default:\n+            serviceURL = getServiceUrlRoot(url) + pageType + \"/\" + contentId + \"/thumbnails/\" + startIdx + \"/\" + pageSize + \"/\" + sortOrder;\n+    }\n+    return serviceURL;\n+}\n+\n+function getServiceUrlRoot(url) {\n+    var serviceRoot = getServerUrl(url) + \"/secure/\";\n+    return serviceRoot;\n+\n+}\n+\n+function getFileRoot(url) {\n+    var fileRoot = getServerUrl(url).substring(0, getServerUrl(url).lastIndexOf('/'));\n+    return fileRoot;\n+}\n+\n+/**\n+    decodeSearchData is an helper function to process the search result page.\n+    It converts the search url parameter into arrary of parameter values.\n+\n+    It converts\n+    type=6&kw=stimson hall|all#and,1925|all&geoIds=&clsIds=&collTypes=&id=all&bDate=-2019&eDate=2030&dExact=1&prGeoId=&origKW=stimson hall|all#and,1925|all\n+    to  {\n+             \"type\": 6\n+             \"kw\": \"stimson hall|all#and,1925|all\"\n+             \"geoIds\": \"\"\n+             \"clsIds\": \"\"\n+             \"collTypes\": \"\"\n+             \"id\": \"all\"\n+             \"bDate\": \"-2019\"\n+             \"eDate\": \"2030\"\n+             \"dExact\": \"1\"\n+             \"prGeoId\": \"\"\n+             \"origKW\": \"stimson hall|all#and,1925|all\"\n+         }\n+**/\n+function decodeSearchData(str) {\n+    var searchParam = str.replace(/(&gt;)/g, \":\");\n+    var param = searchParam.split('&');\n+    var searchData = new Object();\n+    var sparam;\n+    var id;\n+    var value;\n+    for (var i = 0; i < param.length; i++) {\n+        sparam = param[i].split('=');\n+        id = sparam[0];\n+        value = sparam[1];\n+\n+        if (id === 'type') {\n+            searchData[id] = parseInt(value);\n+        } else {\n+            searchData[id] = value;\n+        }\n+    }\n+    return searchData;\n+}\n+\n+var decodeMap = {\n+    '20': ' ',\n+    '21': '!',\n+    '22': '\"',\n+    '23': '#',\n+    '24': '$',\n+    '25': '%',\n+    '26': '&',\n+    '27': \"'\",\n+    '28': '(',\n+    '29': ')',\n+    '2A': '*',\n+    '2B': '+',\n+    '2C': ',',\n+    '2D': '-',\n+    '2E': '.',\n+    '2F': '/',\n+    '30': '0',\n+    '31': '1',\n+    '32': '2',\n+    '33': '3',\n+    '34': '4',\n+    '35': '5',\n+    '36': '6',\n+    '37': '7',\n+    '38': '8',\n+    '39': '9',\n+    '3A': ':',\n+    '3B': ';',\n+    '3C': '<',\n+    '3D': '=',\n+    '3E': '>',\n+    '3F': '?',\n+    '5B': '[',\n+    //              '5C' : '\\\\',\n+    '5D': ']',\n+    '5E': '^',\n+    '5F': '_',\n+    '60': '`',\n+    '7B': '{',\n+    '7C': '|',\n+    '7D': '}',\n+    '7E': '~'\n+};\n+\n+encodeMap = {\n+    ' ': '20',\n+    '!': '21',\n+    '\"': '22',\n+    '#': '23',\n+    '$': '24',\n+    '%': '25',\n+    '&': '26',\n+    \"'\": '27',\n+    '(': '28',\n+    ')': '29',\n+    '*': '2A',\n+    '+': '2B',\n+    ',': '2C',\n+    '-': '2D',\n+    '.': '2E',\n+    '/': '2F',\n+    '0': '30',\n+    '1': '31',\n+    '2': '32',\n+    '3': '33',\n+    '4': '34',\n+    '5': '35',\n+    '6': '36',\n+    '7': '37',\n+    '8': '38',\n+    '9': '39',\n+    ':': '3A',\n+    ';': '3B',\n+    '<': '3C',\n+    '=': '3D',\n+    '>': '3E',\n+    '?': '3F',\n+    '[': '5B',\n+    // '\\\\' : '5C',\n+    ']': '5D',\n+    '^': '5E',\n+    '_': '5F',\n+    '`': '60',\n+    '{': '7B',\n+    '|': '7C',\n+    '}': '7D',\n+    '~': '7E'\n+};\n+\n+/**\n+    Converts two character number character to special character\n+**/\n+function decrypt(s) {","path":"ARTstor.js","position":916,"original_position":916,"commit_id":"0e89f05fb04fba394378209f07cc5f29fff0fcc3","original_commit_id":"0e89f05fb04fba394378209f07cc5f29fff0fcc3","user":{"login":"aurimasv","id":1381759,"avatar_url":"https://avatars.githubusercontent.com/u/1381759?v=3","gravatar_id":"","url":"https://api.github.com/users/aurimasv","html_url":"https://github.com/aurimasv","followers_url":"https://api.github.com/users/aurimasv/followers","following_url":"https://api.github.com/users/aurimasv/following{/other_user}","gists_url":"https://api.github.com/users/aurimasv/gists{/gist_id}","starred_url":"https://api.github.com/users/aurimasv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aurimasv/subscriptions","organizations_url":"https://api.github.com/users/aurimasv/orgs","repos_url":"https://api.github.com/users/aurimasv/repos","events_url":"https://api.github.com/users/aurimasv/events{/privacy}","received_events_url":"https://api.github.com/users/aurimasv/received_events","type":"User","site_admin":false},"body":"Can you explain to me what kind of data you're trying to \"decrypt\" here? Could you show a possible input and and output?","created_at":"2015-07-02T20:44:20Z","updated_at":"2015-07-02T20:44:20Z","html_url":"https://github.com/zotero/translators/pull/899#discussion_r33820811","pull_request_url":"https://api.github.com/repos/zotero/translators/pulls/899","_links":{"self":{"href":"https://api.github.com/repos/zotero/translators/pulls/comments/33820811"},"html":{"href":"https://github.com/zotero/translators/pull/899#discussion_r33820811"},"pull_request":{"href":"https://api.github.com/repos/zotero/translators/pulls/899"}}},"pull_request":{"url":"https://api.github.com/repos/zotero/translators/pulls/899","id":37034563,"html_url":"https://github.com/zotero/translators/pull/899","diff_url":"https://github.com/zotero/translators/pull/899.diff","patch_url":"https://github.com/zotero/translators/pull/899.patch","issue_url":"https://api.github.com/repos/zotero/translators/issues/899","number":899,"state":"open","locked":false,"title":"Enhanced support for new release of Artstor and Shared Shelf Commons","user":{"login":"venturi2k","id":1767476,"avatar_url":"https://avatars.githubusercontent.com/u/1767476?v=3","gravatar_id":"","url":"https://api.github.com/users/venturi2k","html_url":"https://github.com/venturi2k","followers_url":"https://api.github.com/users/venturi2k/followers","following_url":"https://api.github.com/users/venturi2k/following{/other_user}","gists_url":"https://api.github.com/users/venturi2k/gists{/gist_id}","starred_url":"https://api.github.com/users/venturi2k/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/venturi2k/subscriptions","organizations_url":"https://api.github.com/users/venturi2k/orgs","repos_url":"https://api.github.com/users/venturi2k/repos","events_url":"https://api.github.com/users/venturi2k/events{/privacy}","received_events_url":"https://api.github.com/users/venturi2k/received_events","type":"User","site_admin":false},"body":"This release provide enhanced support for Artstor and SSC (Shared Shelf Commons). ","created_at":"2015-06-05T14:09:46Z","updated_at":"2015-07-02T20:44:20Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c5a442aa316c32f27dad6e5da063216a29f8f048","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/zotero/translators/pulls/899/commits","review_comments_url":"https://api.github.com/repos/zotero/translators/pulls/899/comments","review_comment_url":"https://api.github.com/repos/zotero/translators/pulls/comments{/number}","comments_url":"https://api.github.com/repos/zotero/translators/issues/899/comments","statuses_url":"https://api.github.com/repos/zotero/translators/statuses/0e89f05fb04fba394378209f07cc5f29fff0fcc3","head":{"label":"venturi2k:master","ref":"master","sha":"0e89f05fb04fba394378209f07cc5f29fff0fcc3","user":{"login":"venturi2k","id":1767476,"avatar_url":"https://avatars.githubusercontent.com/u/1767476?v=3","gravatar_id":"","url":"https://api.github.com/users/venturi2k","html_url":"https://github.com/venturi2k","followers_url":"https://api.github.com/users/venturi2k/followers","following_url":"https://api.github.com/users/venturi2k/following{/other_user}","gists_url":"https://api.github.com/users/venturi2k/gists{/gist_id}","starred_url":"https://api.github.com/users/venturi2k/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/venturi2k/subscriptions","organizations_url":"https://api.github.com/users/venturi2k/orgs","repos_url":"https://api.github.com/users/venturi2k/repos","events_url":"https://api.github.com/users/venturi2k/events{/privacy}","received_events_url":"https://api.github.com/users/venturi2k/received_events","type":"User","site_admin":false},"repo":{"id":36880548,"name":"translators","full_name":"venturi2k/translators","owner":{"login":"venturi2k","id":1767476,"avatar_url":"https://avatars.githubusercontent.com/u/1767476?v=3","gravatar_id":"","url":"https://api.github.com/users/venturi2k","html_url":"https://github.com/venturi2k","followers_url":"https://api.github.com/users/venturi2k/followers","following_url":"https://api.github.com/users/venturi2k/following{/other_user}","gists_url":"https://api.github.com/users/venturi2k/gists{/gist_id}","starred_url":"https://api.github.com/users/venturi2k/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/venturi2k/subscriptions","organizations_url":"https://api.github.com/users/venturi2k/orgs","repos_url":"https://api.github.com/users/venturi2k/repos","events_url":"https://api.github.com/users/venturi2k/events{/privacy}","received_events_url":"https://api.github.com/users/venturi2k/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/venturi2k/translators","description":"Zotero Translators","fork":true,"url":"https://api.github.com/repos/venturi2k/translators","forks_url":"https://api.github.com/repos/venturi2k/translators/forks","keys_url":"https://api.github.com/repos/venturi2k/translators/keys{/key_id}","collaborators_url":"https://api.github.com/repos/venturi2k/translators/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/venturi2k/translators/teams","hooks_url":"https://api.github.com/repos/venturi2k/translators/hooks","issue_events_url":"https://api.github.com/repos/venturi2k/translators/issues/events{/number}","events_url":"https://api.github.com/repos/venturi2k/translators/events","assignees_url":"https://api.github.com/repos/venturi2k/translators/assignees{/user}","branches_url":"https://api.github.com/repos/venturi2k/translators/branches{/branch}","tags_url":"https://api.github.com/repos/venturi2k/translators/tags","blobs_url":"https://api.github.com/repos/venturi2k/translators/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/venturi2k/translators/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/venturi2k/translators/git/refs{/sha}","trees_url":"https://api.github.com/repos/venturi2k/translators/git/trees{/sha}","statuses_url":"https://api.github.com/repos/venturi2k/translators/statuses/{sha}","languages_url":"https://api.github.com/repos/venturi2k/translators/languages","stargazers_url":"https://api.github.com/repos/venturi2k/translators/stargazers","contributors_url":"https://api.github.com/repos/venturi2k/translators/contributors","subscribers_url":"https://api.github.com/repos/venturi2k/translators/subscribers","subscription_url":"https://api.github.com/repos/venturi2k/translators/subscription","commits_url":"https://api.github.com/repos/venturi2k/translators/commits{/sha}","git_commits_url":"https://api.github.com/repos/venturi2k/translators/git/commits{/sha}","comments_url":"https://api.github.com/repos/venturi2k/translators/comments{/number}","issue_comment_url":"https://api.github.com/repos/venturi2k/translators/issues/comments{/number}","contents_url":"https://api.github.com/repos/venturi2k/translators/contents/{+path}","compare_url":"https://api.github.com/repos/venturi2k/translators/compare/{base}...{head}","merges_url":"https://api.github.com/repos/venturi2k/translators/merges","archive_url":"https://api.github.com/repos/venturi2k/translators/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/venturi2k/translators/downloads","issues_url":"https://api.github.com/repos/venturi2k/translators/issues{/number}","pulls_url":"https://api.github.com/repos/venturi2k/translators/pulls{/number}","milestones_url":"https://api.github.com/repos/venturi2k/translators/milestones{/number}","notifications_url":"https://api.github.com/repos/venturi2k/translators/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/venturi2k/translators/labels{/name}","releases_url":"https://api.github.com/repos/venturi2k/translators/releases{/id}","created_at":"2015-06-04T15:57:03Z","updated_at":"2015-06-04T15:57:05Z","pushed_at":"2015-07-02T20:27:37Z","git_url":"git://github.com/venturi2k/translators.git","ssh_url":"git@github.com:venturi2k/translators.git","clone_url":"https://github.com/venturi2k/translators.git","svn_url":"https://github.com/venturi2k/translators","homepage":"http://www.zotero.org/support/dev/translators","size":11348,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"zotero:master","ref":"master","sha":"6de7970e409e2bbacd100b0172eba626068491d8","user":{"login":"zotero","id":891917,"avatar_url":"https://avatars.githubusercontent.com/u/891917?v=3","gravatar_id":"","url":"https://api.github.com/users/zotero","html_url":"https://github.com/zotero","followers_url":"https://api.github.com/users/zotero/followers","following_url":"https://api.github.com/users/zotero/following{/other_user}","gists_url":"https://api.github.com/users/zotero/gists{/gist_id}","starred_url":"https://api.github.com/users/zotero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zotero/subscriptions","organizations_url":"https://api.github.com/users/zotero/orgs","repos_url":"https://api.github.com/users/zotero/repos","events_url":"https://api.github.com/users/zotero/events{/privacy}","received_events_url":"https://api.github.com/users/zotero/received_events","type":"Organization","site_admin":false},"repo":{"id":1991863,"name":"translators","full_name":"zotero/translators","owner":{"login":"zotero","id":891917,"avatar_url":"https://avatars.githubusercontent.com/u/891917?v=3","gravatar_id":"","url":"https://api.github.com/users/zotero","html_url":"https://github.com/zotero","followers_url":"https://api.github.com/users/zotero/followers","following_url":"https://api.github.com/users/zotero/following{/other_user}","gists_url":"https://api.github.com/users/zotero/gists{/gist_id}","starred_url":"https://api.github.com/users/zotero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zotero/subscriptions","organizations_url":"https://api.github.com/users/zotero/orgs","repos_url":"https://api.github.com/users/zotero/repos","events_url":"https://api.github.com/users/zotero/events{/privacy}","received_events_url":"https://api.github.com/users/zotero/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/zotero/translators","description":"Zotero Translators","fork":false,"url":"https://api.github.com/repos/zotero/translators","forks_url":"https://api.github.com/repos/zotero/translators/forks","keys_url":"https://api.github.com/repos/zotero/translators/keys{/key_id}","collaborators_url":"https://api.github.com/repos/zotero/translators/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/zotero/translators/teams","hooks_url":"https://api.github.com/repos/zotero/translators/hooks","issue_events_url":"https://api.github.com/repos/zotero/translators/issues/events{/number}","events_url":"https://api.github.com/repos/zotero/translators/events","assignees_url":"https://api.github.com/repos/zotero/translators/assignees{/user}","branches_url":"https://api.github.com/repos/zotero/translators/branches{/branch}","tags_url":"https://api.github.com/repos/zotero/translators/tags","blobs_url":"https://api.github.com/repos/zotero/translators/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/zotero/translators/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/zotero/translators/git/refs{/sha}","trees_url":"https://api.github.com/repos/zotero/translators/git/trees{/sha}","statuses_url":"https://api.github.com/repos/zotero/translators/statuses/{sha}","languages_url":"https://api.github.com/repos/zotero/translators/languages","stargazers_url":"https://api.github.com/repos/zotero/translators/stargazers","contributors_url":"https://api.github.com/repos/zotero/translators/contributors","subscribers_url":"https://api.github.com/repos/zotero/translators/subscribers","subscription_url":"https://api.github.com/repos/zotero/translators/subscription","commits_url":"https://api.github.com/repos/zotero/translators/commits{/sha}","git_commits_url":"https://api.github.com/repos/zotero/translators/git/commits{/sha}","comments_url":"https://api.github.com/repos/zotero/translators/comments{/number}","issue_comment_url":"https://api.github.com/repos/zotero/translators/issues/comments{/number}","contents_url":"https://api.github.com/repos/zotero/translators/contents/{+path}","compare_url":"https://api.github.com/repos/zotero/translators/compare/{base}...{head}","merges_url":"https://api.github.com/repos/zotero/translators/merges","archive_url":"https://api.github.com/repos/zotero/translators/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/zotero/translators/downloads","issues_url":"https://api.github.com/repos/zotero/translators/issues{/number}","pulls_url":"https://api.github.com/repos/zotero/translators/pulls{/number}","milestones_url":"https://api.github.com/repos/zotero/translators/milestones{/number}","notifications_url":"https://api.github.com/repos/zotero/translators/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/zotero/translators/labels{/name}","releases_url":"https://api.github.com/repos/zotero/translators/releases{/id}","created_at":"2011-07-03T17:40:38Z","updated_at":"2015-06-26T10:25:13Z","pushed_at":"2015-07-02T20:27:38Z","git_url":"git://github.com/zotero/translators.git","ssh_url":"git@github.com:zotero/translators.git","clone_url":"https://github.com/zotero/translators.git","svn_url":"https://github.com/zotero/translators","homepage":"http://www.zotero.org/support/dev/translators","size":16922,"stargazers_count":149,"watchers_count":149,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":125,"mirror_url":null,"open_issues_count":121,"forks":125,"open_issues":121,"watchers":149,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/zotero/translators/pulls/899"},"html":{"href":"https://github.com/zotero/translators/pull/899"},"issue":{"href":"https://api.github.com/repos/zotero/translators/issues/899"},"comments":{"href":"https://api.github.com/repos/zotero/translators/issues/899/comments"},"review_comments":{"href":"https://api.github.com/repos/zotero/translators/pulls/899/comments"},"review_comment":{"href":"https://api.github.com/repos/zotero/translators/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/zotero/translators/pulls/899/commits"},"statuses":{"href":"https://api.github.com/repos/zotero/translators/statuses/0e89f05fb04fba394378209f07cc5f29fff0fcc3"}}}}