Advertisement
Guest User

Untitled

a guest
Feb 13th, 2019
515
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 233.70 KB | None | 0 0
  1. root@bananapim2:/var/www/nextcloud/data# cat nextcloud.log
  2.  
  3. {"reqId":"0GimkrGBxbF7eqLgjUqi","level":3,"time":"2019-02-13T22:00:03+00:00","remoteAddr":"","user":"--","app":"PHP","method":"","url":"--","message":"file_get_contents(\/var\/www\/nextcloud\/data\/news\/config\/config.ini): failed to open stream: No such file or directory at \/var\/www\/nextcloud\/lib\/private\/Files\/Storage\/Local.php#216","userAgent":"--","version":"15.0.4.0"}
  4. {"reqId":"0GimkrGBxbF7eqLgjUqi","level":2,"time":"2019-02-13T22:00:03+00:00","remoteAddr":"","user":"--","app":"news","method":"","url":"--","message":"Configuration invalid. Ignoring values.","userAgent":"--","version":"15.0.4.0"}
  5. {"reqId":"kWrOLjJiOSKRG1QIrtAS","level":3,"time":"2019-02-13T22:02:54+00:00","remoteAddr":"","user":"--","app":"PHP","method":"","url":"--","message":"file_get_contents(\/var\/www\/nextcloud\/data\/news\/config\/config.ini): failed to open stream: No such file or directory at \/var\/www\/nextcloud\/lib\/private\/Files\/Storage\/Local.php#216","userAgent":"--","version":"15.0.4.0"}
  6. {"reqId":"kWrOLjJiOSKRG1QIrtAS","level":2,"time":"2019-02-13T22:02:54+00:00","remoteAddr":"","user":"--","app":"news","method":"","url":"--","message":"Configuration invalid. Ignoring values.","userAgent":"--","version":"15.0.4.0"}
  7. {"reqId":"ZwWhTaqUy0oDh9KawGds","level":3,"time":"2019-02-13T22:03:01+00:00","remoteAddr":"","user":"--","app":"PHP","method":"","url":"--","message":"file_get_contents(\/var\/www\/nextcloud\/data\/news\/config\/config.ini): failed to open stream: No such file or directory at \/var\/www\/nextcloud\/lib\/private\/Files\/Storage\/Local.php#216","userAgent":"--","version":"15.0.4.0"}
  8. {"reqId":"ZwWhTaqUy0oDh9KawGds","level":2,"time":"2019-02-13T22:03:01+00:00","remoteAddr":"","user":"--","app":"news","method":"","url":"--","message":"Configuration invalid. Ignoring values.","userAgent":"--","version":"15.0.4.0"}
  9. {"reqId":"XGSV38Cosp8AAAc73lcAAE4V","level":3,"time":"2019-02-13T22:10:40+00:00","remoteAddr":"192.168.178.152","user":"--","app":"PHP","method":"GET","url":"\/index.php\/login","message":"touch(): Unable to create file \/var\/www\/nextcloud\/data\/appdata_ocr4wcw6iijv\/js\/core\/merged-template-prepend.js because No such file or directory at \/var\/www\/nextcloud\/lib\/private\/Files\/Storage\/Local.php#206","userAgent":"Mozilla\/5.0 (Windows NT 6.1; Win64; x64; rv:65.0) Gecko\/20100101 Firefox\/65.0","version":"15.0.4.0"}
  10. {"reqId":"XGSV38Cosp8AAAc73lcAAE4V","level":3,"time":"2019-02-13T22:10:40+00:00","remoteAddr":"192.168.178.152","user":"--","app":"PHP","method":"GET","url":"\/index.php\/login","message":"touch(): Unable to create file \/var\/www\/nextcloud\/data\/appdata_ocr4wcw6iijv\/js\/core\/merged-template-prepend.js.deps because No such file or directory at \/var\/www\/nextcloud\/lib\/private\/Files\/Storage\/Local.php#206","userAgent":"Mozilla\/5.0 (Windows NT 6.1; Win64; x64; rv:65.0) Gecko\/20100101 Firefox\/65.0","version":"15.0.4.0"}
  11. {"reqId":"XGSV38Cosp8AAAc73lcAAE4V","level":3,"time":"2019-02-13T22:10:40+00:00","remoteAddr":"192.168.178.152","user":"--","app":"PHP","method":"GET","url":"\/index.php\/login","message":"touch(): Unable to create file \/var\/www\/nextcloud\/data\/appdata_ocr4wcw6iijv\/js\/core\/merged-template-prepend.js.gzip because No such file or directory at \/var\/www\/nextcloud\/lib\/private\/Files\/Storage\/Local.php#206","userAgent":"Mozilla\/5.0 (Windows NT 6.1; Win64; x64; rv:65.0) Gecko\/20100101 Firefox\/65.0","version":"15.0.4.0"}
  12. {"reqId":"XGSV38Cosp8AAAc73lcAAE4V","level":3,"time":"2019-02-13T22:10:40+00:00","remoteAddr":"192.168.178.152","user":"--","app":"index","method":"GET","url":"\/index.php\/login","message":{"Exception":"OCP\\Files\\NotFoundException","Message":"","Code":0,"Trace":[{"file":"\/var\/www\/nextcloud\/lib\/private\/Files\/Node\/Node.php","line":216,"function":"getFileInfo","class":"OC\\Files\\Node\\Node","type":"->","args":[]},{"file":"\/var\/www\/nextcloud\/lib\/private\/Files\/Node\/Node.php","line":117,"function":"getPermissions","class":"OC\\Files\\Node\\Node","type":"->","args":[]},{"file":"\/var\/www\/nextcloud\/lib\/private\/Files\/Node\/File.php","line":64,"function":"checkPermissions","class":"OC\\Files\\Node\\Node","type":"->","args":[2]},{"file":"\/var\/www\/nextcloud\/lib\/private\/Files\/SimpleFS\/SimpleFile.php","line":104,"function":"putContent","class":"OC\\Files\\Node\\File","type":"->","args":["(function($) {\n\t$.widget('oc.ocdialog', {\n\t\toptions: {\n\t\t\twidth: 'auto',\n\t\t\theight: 'auto',\n\t\t\tcloseButton: true,\n\t\t\tcloseOnEscape: true,\n\t\t\tmodal: false\n\t\t},\n\t\t_create: function() {\n\t\t\tvar self = this;\n\n\t\t\tthis.originalCss = {\n\t\t\t\tdisplay: this.element[0].style.display,\n\t\t\t\twidth: this.element[0].style.width,\n\t\t\t\theight: this.element[0].style.height\n\t\t\t};\n\n\t\t\tthis.originalTitle = this.element.attr('title');\n\t\t\tthis.options.title = this.options.title || this.originalTitle;\n\n\t\t\tthis.$dialog = $('<div class=\"oc-dialog\" \/>')\n\t\t\t\t.attr({\n\t\t\t\t\t\/\/ Setting tabIndex makes the div focusable\n\t\t\t\t\ttabIndex: -1,\n\t\t\t\t\trole: 'dialog'\n\t\t\t\t})\n\t\t\t\t.insertBefore(this.element);\n\t\t\tthis.$dialog.append(this.element.detach());\n\t\t\tthis.element.removeAttr('title').addClass('oc-dialog-content').appendTo(this.$dialog);\n\n\t\t\tthis.$dialog.css({\n\t\t\t\tdisplay: 'inline-block',\n\t\t\t\tposition: 'fixed'\n\t\t\t});\n\n\t\t\t$(document).on('keydown keyup', function(event) {\n\t\t\t\tif (\n\t\t\t\t\tevent.target !== self.$dialog.get(0) &&\n\t\t\t\t\tself.$dialog.find($(event.target)).length === 0\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\/\/ Escape\n\t\t\t\tif (\n\t\t\t\t\tevent.keyCode === 27 &&\n\t\t\t\t\tevent.type === 'keydown' &&\n\t\t\t\t\tself.options.closeOnEscape\n\t\t\t\t) {\n\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\tself.close();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\/\/ Enter\n\t\t\t\tif(event.keyCode === 13) {\n\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\tif(event.type === 'keyup') {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t\/\/ If no button is selected we trigger the primary\n\t\t\t\t\tif (\n\t\t\t\t\t\tself.$buttonrow &&\n\t\t\t\t\t\tself.$buttonrow.find($(event.target)).length === 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tvar $button = self.$buttonrow.find('button.primary');\n\t\t\t\t\t\tif($button && !$button.prop('disabled')) {\n\t\t\t\t\t\t\t$button.trigger('click');\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if(self.$buttonrow) {\n\t\t\t\t\t\t$(event.target).trigger('click');\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis._setOptions(this.options);\n\t\t\tthis._createOverlay();\n\t\t},\n\t\t_init: function() {\n\t\t\tthis.$dialog.focus();\n\t\t\tthis._trigger('open');\n\t\t},\n\t\t_setOption: function(key, value) {\n\t\t\tvar self = this;\n\t\t\tswitch(key) {\n\t\t\t\tcase 'title':\n\t\t\t\t\tif(this.$title) {\n\t\t\t\t\t\tthis.$title.text(value);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar $title = $('<h2 class=\"oc-dialog-title\">'\n\t\t\t\t\t\t\t+ value\n\t\t\t\t\t\t\t+ '<\/h2>');\n\t\t\t\t\t\tthis.$title = $title.prependTo(this.$dialog);\n\t\t\t\t\t}\n\t\t\t\t\tthis._setSizes();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'buttons':\n\t\t\t\t\tif(this.$buttonrow) {\n\t\t\t\t\t\tthis.$buttonrow.empty();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar $buttonrow = $('<div class=\"oc-dialog-buttonrow\" \/>');\n\t\t\t\t\t\tthis.$buttonrow = $buttonrow.appendTo(this.$dialog);\n\t\t\t\t\t}\n\t\t\t\t\tif (value.length === 1) {\n\t\t\t\t\t\tthis.$buttonrow.addClass('onebutton');\n\t\t\t\t\t} else if (value.length === 2) {\n\t\t\t\t\t\tthis.$buttonrow.addClass('twobuttons');\n\t\t\t\t\t} else if (value.length === 3) {\n\t\t\t\t\t\tthis.$buttonrow.addClass('threebuttons');\n\t\t\t\t\t}\n\t\t\t\t\t$.each(value, function(idx, val) {\n\t\t\t\t\t\tvar $button = $('<button>').text(val.text);\n\t\t\t\t\t\tif (val.classes) {\n\t\t\t\t\t\t\t$button.addClass(val.classes);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(val.defaultButton) {\n\t\t\t\t\t\t\t$button.addClass('primary');\n\t\t\t\t\t\t\tself.$defaultButton = $button;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tself.$buttonrow.append($button);\n\t\t\t\t\t\t$button.click(function() {\n\t\t\t\t\t\t\tval.click.apply(self.element[0], arguments);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t\tthis.$buttonrow.find('button')\n\t\t\t\t\t\t.on('focus', function(event) {\n\t\t\t\t\t\t\tself.$buttonrow.find('button').removeClass('primary');\n\t\t\t\t\t\t\t$(this).addClass('primary');\n\t\t\t\t\t\t});\n\t\t\t\t\tthis._setSizes();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'style':\n\t\t\t\t\tif (value.buttons !== undefined) {\n\t\t\t\t\t\tthis.$buttonrow.addClass(value.buttons);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'closeButton':\n\t\t\t\t\tif(value) {\n\t\t\t\t\t\tvar $closeButton = $('<a class=\"oc-dialog-close\"><\/a>');\n\t\t\t\t\t\tthis.$dialog.prepend($closeButton);\n\t\t\t\t\t\t$closeButton.on('click', function() {\n\t\t\t\t\t\t\tself.close();\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.$dialog.find('.oc-dialog-close').remove();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'width':\n\t\t\t\t\tthis.$dialog.css('width', value);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'height':\n\t\t\t\t\tthis.$dialog.css('height', value);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'close':\n\t\t\t\t\tthis.closeCB = value;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\/\/this._super(key, value);\n\t\t\t$.Widget.prototype._setOption.apply(this, arguments );\n\t\t},\n\t\t_setOptions: function(options) {\n\t\t\t\/\/this._super(options);\n\t\t\t$.Widget.prototype._setOptions.apply(this, arguments);\n\t\t},\n\t\t_setSizes: function() {\n\t\t\tvar lessHeight = 0;\n\t\t\tif(this.$title) {\n\t\t\t\tlessHeight += this.$title.outerHeight(true);\n\t\t\t}\n\t\t\tif(this.$buttonrow) {\n\t\t\t\tlessHeight += this.$buttonrow.outerHeight(true);\n\t\t\t}\n\t\t\tthis.element.css({\n\t\t\t\t'height': 'calc(100% - ' + lessHeight + 'px)'\n\t\t\t});\n\t\t},\n\t\t_createOverlay: function() {\n\t\t\tif(!this.options.modal) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar self = this;\n\t\t\tthis.overlay = $('<div>')\n\t\t\t\t.addClass('oc-dialog-dim')\n\t\t\t\t.appendTo($('#content'));\n\t\t\tthis.overlay.on('click keydown keyup', function(event) {\n\t\t\t\tif(event.target !== self.$dialog.get(0) && self.$dialog.find($(event.target)).length === 0) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\t_destroyOverlay: function() {\n\t\t\tif (!this.options.modal) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this.overlay) {\n\t\t\t\tthis.overlay.off('click keydown keyup');\n\t\t\t\tthis.overlay.remove();\n\t\t\t\tthis.overlay = null;\n\t\t\t}\n\t\t},\n\t\twidget: function() {\n\t\t\treturn this.$dialog;\n\t\t},\n\t\tclose: function() {\n\t\t\tthis._destroyOverlay();\n\t\t\tvar self = this;\n\t\t\t\/\/ Ugly hack to catch remaining keyup events.\n\t\t\tsetTimeout(function() {\n\t\t\t\tself._trigger('close', self);\n\t\t\t}, 200);\n\n\t\t\tself.$dialog.remove();\n\t\t\tthis.destroy();\n\t\t},\n\t\tdestroy: function() {\n\t\t\tif(this.$title) {\n\t\t\t\tthis.$title.remove();\n\t\t\t}\n\t\t\tif(this.$buttonrow) {\n\t\t\t\tthis.$buttonrow.remove();\n\t\t\t}\n\n\t\t\tif(this.originalTitle) {\n\t\t\t\tthis.element.attr('title', this.originalTitle);\n\t\t\t}\n\t\t\tthis.element.removeClass('oc-dialog-content')\n\t\t\t\t\t.css(this.originalCss).detach().insertBefore(this.$dialog);\n\t\t\tthis.$dialog.remove();\n\t\t}\n\t});\n}(jQuery));\n\n\n\/**\n * ownCloud\n *\n * @author Bartek Przybylski, Christopher Sch\u00e4pers, Thomas Tanghus\n * @copyright 2012 Bartek Przybylski bartek@alefzero.eu\n *\n * This library is free software; you can redistribute it and\/or\n * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library 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\n * License along with this library.  If not, see <http:\/\/www.gnu.org\/licenses\/>.\n *\n *\/\n\n\/* global alert *\/\n\n\/**\n * this class to ease the usage of jquery dialogs\n * @lends OC.dialogs\n *\/\nvar OCdialogs = {\n\t\/\/ dialog button types\n\tYES_NO_BUTTONS:\t\t70,\n\tOK_BUTTONS:\t\t71,\n\n\tFILEPICKER_TYPE_CHOOSE: 1,\n\tFILEPICKER_TYPE_MOVE: 2,\n\tFILEPICKER_TYPE_COPY: 3,\n\tFILEPICKER_TYPE_COPY_MOVE: 4,\n\n\t\/\/ used to name each dialog\n\tdialogsCounter: 0,\n\t\/**\n\t* displays alert dialog\n\t* @param text content of dialog\n\t* @param title dialog title\n\t* @param callback which will be triggered when user presses OK\n\t* @param modal make the dialog modal\n\t*\/\n\talert:function(text, title, callback, modal) {\n\t\tthis.message(\n\t\t\ttext,\n\t\t\ttitle,\n\t\t\t'alert',\n\t\t\tOCdialogs.OK_BUTTON,\n\t\t\tcallback,\n\t\t\tmodal\n\t\t);\n\t},\n\t\/**\n\t* displays info dialog\n\t* @param text content of dialog\n\t* @param title dialog title\n\t* @param callback which will be triggered when user presses OK\n\t* @param modal make the dialog modal\n\t*\/\n\tinfo:function(text, title, callback, modal) {\n\t\tthis.message(text, title, 'info', OCdialogs.OK_BUTTON, callback, modal);\n\t},\n\t\/**\n\t* displays confirmation dialog\n\t* @param text content of dialog\n\t* @param title dialog title\n\t* @param callback which will be triggered when user presses YES or NO\n\t*        (true or false would be passed to callback respectively)\n\t* @param modal make the dialog modal\n\t*\/\n\tconfirm:function(text, title, callback, modal) {\n\t\treturn this.message(\n\t\t\ttext,\n\t\t\ttitle,\n\t\t\t'notice',\n\t\t\tOCdialogs.YES_NO_BUTTONS,\n\t\t\tcallback,\n\t\t\tmodal\n\t\t);\n\t},\n\t\/**\n\t* displays confirmation dialog\n\t* @param text content of dialog\n\t* @param title dialog title\n\t* @param callback which will be triggered when user presses YES or NO\n\t*        (true or false would be passed to callback respectively)\n\t* @param modal make the dialog modal\n\t*\/\n\tconfirmHtml:function(text, title, callback, modal) {\n\t\treturn this.message(\n\t\t\ttext,\n\t\t\ttitle,\n\t\t\t'notice',\n\t\t\tOCdialogs.YES_NO_BUTTONS,\n\t\t\tcallback,\n\t\t\tmodal,\n\t\t\ttrue\n\t\t);\n\t},\n\t\/**\n\t * displays prompt dialog\n\t * @param text content of dialog\n\t * @param title dialog title\n\t * @param callback which will be triggered when user presses YES or NO\n\t *        (true or false would be passed to callback respectively)\n\t * @param modal make the dialog modal\n\t * @param name name of the input field\n\t * @param password whether the input should be a password input\n\t *\/\n\tprompt: function (text, title, callback, modal, name, password) {\n\t\treturn $.when(this._getMessageTemplate()).then(function ($tmpl) {\n\t\t\tvar dialogName = 'oc-dialog-' + OCdialogs.dialogsCounter + '-content';\n\t\t\tvar dialogId = '#' + dialogName;\n\t\t\tvar $dlg = $tmpl.octemplate({\n\t\t\t\tdialog_name: dialogName,\n\t\t\t\ttitle      : title,\n\t\t\t\tmessage    : text,\n\t\t\t\ttype       : 'notice'\n\t\t\t});\n\t\t\tvar input = $('<input\/>');\n\t\t\tinput.attr('type', password ? 'password' : 'text').attr('id', dialogName + '-input').attr('placeholder', name);\n\t\t\tvar label = $('<label\/>').attr('for', dialogName + '-input').text(name + ': ');\n\t\t\t$dlg.append(label);\n\t\t\t$dlg.append(input);\n\t\t\tif (modal === undefined) {\n\t\t\t\tmodal = false;\n\t\t\t}\n\t\t\t$('body').append($dlg);\n\n\t\t\t\/\/ wrap callback in _.once():\n\t\t\t\/\/ only call callback once and not twice (button handler and close\n\t\t\t\/\/ event) but call it for the close event, if ESC or the x is hit\n\t\t\tif (callback !== undefined) {\n\t\t\t\tcallback = _.once(callback);\n\t\t\t}\n\n\t\t\tvar buttonlist = [{\n\t\t\t\t\ttext : t('core', 'No'),\n\t\t\t\t\tclick: function () {\n\t\t\t\t\t\tif (callback !== undefined) {\n\t\t\t\t\t\t\tcallback(false, input.val());\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$(dialogId).ocdialog('close');\n\t\t\t\t\t}\n\t\t\t\t}, {\n\t\t\t\t\ttext         : t('core', 'Yes'),\n\t\t\t\t\tclick        : function () {\n\t\t\t\t\t\tif (callback !== undefined) {\n\t\t\t\t\t\t\tcallback(true, input.val());\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$(dialogId).ocdialog('close');\n\t\t\t\t\t},\n\t\t\t\t\tdefaultButton: true\n\t\t\t\t}\n\t\t\t];\n\n\t\t\t$(dialogId).ocdialog({\n\t\t\t\tcloseOnEscape: true,\n\t\t\t\tmodal        : modal,\n\t\t\t\tbuttons      : buttonlist,\n\t\t\t\tclose        : function() {\n\t\t\t\t\t\/\/ callback is already fired if Yes\/No is clicked directly\n\t\t\t\t\tif (callback !== undefined) {\n\t\t\t\t\t\tcallback(false, input.val());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tinput.focus();\n\t\t\tOCdialogs.dialogsCounter++;\n\t\t});\n\t},\n\t\/**\n\t * show a file picker to pick a file from\n\t *\n\t * In order to pick several types of mime types they need to be passed as an\n\t * array of strings.\n\t *\n\t * When no mime type filter is given only files can be selected. In order to\n\t * be able to select both files and folders \"['*', 'httpd\/unix-directory']\"\n\t * should be used instead.\n\t *\n\t * @param title dialog title\n\t * @param callback which will be triggered when user presses Choose\n\t * @param multiselect whether it should be possible to select multiple files\n\t * @param mimetypeFilter mimetype to filter by - directories will always be included\n\t * @param modal make the dialog modal\n\t * @param type Type of file picker : Choose, copy, move, copy and move\n\t*\/\n\tfilepicker:function(title, callback, multiselect, mimetypeFilter, modal, type) {\n\t\tvar self = this;\n\n\t\tthis.filepicker.sortField = 'name';\n\t\tthis.filepicker.sortOrder = 'asc';\n\t\t\/\/ avoid opening the picker twice\n\t\tif (this.filepicker.loading) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (type === undefined) {\n\t\t\ttype = this.FILEPICKER_TYPE_CHOOSE;\n\t\t}\n\n\t\tvar emptyText = t('core', 'No files in here');\n\t\tif (type === this.FILEPICKER_TYPE_COPY || type === this.FILEPICKER_TYPE_MOVE || type === this.FILEPICKER_TYPE_COPY_MOVE) {\n\t\t\temptyText = t('core', 'No more subfolders in here');\n\t\t}\n\n\t\tthis.filepicker.loading = true;\n\t\tthis.filepicker.filesClient = (OCA.Sharing && OCA.Sharing.PublicApp && OCA.Sharing.PublicApp.fileList)? OCA.Sharing.PublicApp.fileList.filesClient: OC.Files.getClient();\n\n\t\t$.when(this._getFilePickerTemplate()).then(function($tmpl) {\n\t\t\tself.filepicker.loading = false;\n\t\t\tvar dialogName = 'oc-dialog-filepicker-content';\n\t\t\tif(self.$filePicker) {\n\t\t\t\tself.$filePicker.ocdialog('close');\n\t\t\t}\n\n\t\t\tif (mimetypeFilter === undefined || mimetypeFilter === null) {\n\t\t\t\tmimetypeFilter = [];\n\t\t\t}\n\t\t\tif (typeof(mimetypeFilter) === \"string\") {\n\t\t\t\tmimetypeFilter = [mimetypeFilter];\n\t\t\t}\n\n\t\t\tself.$filePicker = $tmpl.octemplate({\n\t\t\t\tdialog_name: dialogName,\n\t\t\t\ttitle: title,\n\t\t\t\temptytext: emptyText\n\t\t\t}).data('path', '').data('multiselect', multiselect).data('mimetype', mimetypeFilter);\n\n\t\t\tif (modal === undefined) {\n\t\t\t\tmodal = false;\n\t\t\t}\n\t\t\tif (multiselect === undefined) {\n\t\t\t\tmultiselect = false;\n\t\t\t}\n\n\t\t\t\/\/ No grid for IE!\n\t\t\tif (OC.Util.isIE()) {\n\t\t\t\tself.$filePicker.find('#picker-view-toggle').remove();\n\t\t\t\tself.$filePicker.find('#picker-filestable').removeClass('view-grid');\n\t\t\t}\n\n\t\t\t$('body').append(self.$filePicker);\n\n\t\t\tself.$showGridView = $('input#picker-showgridview');\n\t\t\tself.$showGridView.on('change', _.bind(self._onGridviewChange, self));\n\n\t\t\tif (!OC.Util.isIE()) {\n\t\t\t\tself._getGridSettings();\n\t\t\t}\n\n\t\t\tself.$filePicker.ready(function() {\n\t\t\t\tself.$fileListHeader = self.$filePicker.find('.filelist thead tr');\n\t\t\t\tself.$filelist = self.$filePicker.find('.filelist tbody');\n\t\t\t\tself.$filelistContainer = self.$filePicker.find('.filelist-container');\n\t\t\t\tself.$dirTree = self.$filePicker.find('.dirtree');\n\t\t\t\tself.$dirTree.on('click', 'div:not(:last-child)', self, function (event) {\n\t\t\t\t\tself._handleTreeListSelect(event, type);\n\t\t\t\t});\n\t\t\t\tself.$filelist.on('click', 'tr', function(event) {\n\t\t\t\t\tself._handlePickerClick(event, $(this), type);\n\t\t\t\t});\n\t\t\t\tself.$fileListHeader.on('click', 'a', function(event) {\n\t\t\t\t\tvar dir = self.$filePicker.data('path');\n\t\t\t\t\tself.filepicker.sortField = $(event.currentTarget).data('sort');\n\t\t\t\t\tself.filepicker.sortOrder = self.filepicker.sortOrder === 'asc' ? 'desc' : 'asc';\n\t\t\t\t\tself._fillFilePicker(dir);\n\t\t\t\t});\n\t\t\t\tself._fillFilePicker('');\n\t\t\t});\n\n\t\t\t\/\/ build buttons\n\t\t\tvar functionToCall = function(returnType) {\n\t\t\t\tif (callback !== undefined) {\n\t\t\t\t\tvar datapath;\n\t\t\t\t\tif (multiselect === true) {\n\t\t\t\t\t\tdatapath = [];\n\t\t\t\t\t\tself.$filelist.find('tr.filepicker_element_selected').each(function(index, element) {\n\t\t\t\t\t\t\tdatapath.push(self.$filePicker.data('path') + '\/' + $(element).data('entryname'));\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdatapath = self.$filePicker.data('path');\n\t\t\t\t\t\tvar selectedName = self.$filelist.find('tr.filepicker_element_selected').data('entryname');\n\t\t\t\t\t\tif (selectedName) {\n\t\t\t\t\t\t\tdatapath += '\/' + selectedName;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcallback(datapath, returnType);\n\t\t\t\t\tself.$filePicker.ocdialog('close');\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tvar chooseCallback = function () {\n\t\t\t\tfunctionToCall(OCdialogs.FILEPICKER_TYPE_CHOOSE);\n\t\t\t};\n\n\t\t\tvar copyCallback = function () {\n\t\t\t\tfunctionToCall(OCdialogs.FILEPICKER_TYPE_COPY);\n\t\t\t};\n\n\t\t\tvar moveCallback = function () {\n\t\t\t\tfunctionToCall(OCdialogs.FILEPICKER_TYPE_MOVE);\n\t\t\t};\n\n\t\t\tvar buttonlist = [];\n\t\t\tif (type === OCdialogs.FILEPICKER_TYPE_CHOOSE) {\n\t\t\t\tbuttonlist.push({\n\t\t\t\t\ttext: t('core', 'Choose'),\n\t\t\t\t\tclick: chooseCallback,\n\t\t\t\t\tdefaultButton: true\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tif (type === OCdialogs.FILEPICKER_TYPE_COPY || type === OCdialogs.FILEPICKER_TYPE_COPY_MOVE) {\n\t\t\t\t\tbuttonlist.push({\n\t\t\t\t\t\ttext: t('core', 'Copy'),\n\t\t\t\t\t\tclick: copyCallback,\n\t\t\t\t\t\tdefaultButton: false\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (type === OCdialogs.FILEPICKER_TYPE_MOVE || type === OCdialogs.FILEPICKER_TYPE_COPY_MOVE) {\n\t\t\t\t\tbuttonlist.push({\n\t\t\t\t\t\ttext: t('core', 'Move'),\n\t\t\t\t\t\tclick: moveCallback,\n\t\t\t\t\t\tdefaultButton: true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tself.$filePicker.ocdialog({\n\t\t\t\tcloseOnEscape: true,\n\t\t\t\t\/\/ max-width of 600\n\t\t\t\twidth: 600,\n\t\t\t\theight: 500,\n\t\t\t\tmodal: modal,\n\t\t\t\tbuttons: buttonlist,\n\t\t\t\tstyle: {\n\t\t\t\t\tbuttons: 'aside',\n\t\t\t\t},\n\t\t\t\tclose: function() {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t$(this).ocdialog('destroy').remove();\n\t\t\t\t\t} catch(e) {}\n\t\t\t\t\tself.$filePicker = null;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t\/\/ We can access primary class only from oc-dialog.\n\t\t\t\/\/ Hence this is one of the approach to get the choose button.\n\t\t\tvar getOcDialog = self.$filePicker.closest('.oc-dialog');\n\t\t\tvar buttonEnableDisable = getOcDialog.find('.primary');\n\t\t\tif (self.$filePicker.data('mimetype').indexOf(\"httpd\/unix-directory\") !== -1) {\n\t\t\t\tbuttonEnableDisable.prop(\"disabled\", false);\n\t\t\t} else {\n\t\t\t\tbuttonEnableDisable.prop(\"disabled\", true);\n\t\t\t}\n\t\t})\n\t\t.fail(function(status, error) {\n\t\t\t\/\/ If the method is called while navigating away\n\t\t\t\/\/ from the page, it is probably not needed ;)\n\t\t\tself.filepicker.loading = false;\n\t\t\tif(status !== 0) {\n\t\t\t\talert(t('core', 'Error loading file picker template: {error}', {error: error}));\n\t\t\t}\n\t\t});\n\t},\n\t\/**\n\t * Displays raw dialog\n\t * You better use a wrapper instead ...\n\t*\/\n\tmessage:function(content, title, dialogType, buttons, callback, modal, allowHtml) {\n\t\treturn $.when(this._getMessageTemplate()).then(function($tmpl) {\n\t\t\tvar dialogName = 'oc-dialog-' + OCdialogs.dialogsCounter + '-content';\n\t\t\tvar dialogId = '#' + dialogName;\n\t\t\tvar $dlg = $tmpl.octemplate({\n\t\t\t\tdialog_name: dialogName,\n\t\t\t\ttitle: title,\n\t\t\t\tmessage: content,\n\t\t\t\ttype: dialogType\n\t\t\t}, allowHtml ? {escapeFunction: ''} : {});\n\t\t\tif (modal === undefined) {\n\t\t\t\tmodal = false;\n\t\t\t}\n\t\t\t$('body').append($dlg);\n\t\t\tvar buttonlist = [];\n\t\t\tswitch (buttons) {\n\t\t\tcase OCdialogs.YES_NO_BUTTONS:\n\t\t\t\tbuttonlist = [{\n\t\t\t\t\ttext: t('core', 'No'),\n\t\t\t\t\tclick: function(){\n\t\t\t\t\t\tif (callback !== undefined) {\n\t\t\t\t\t\t\tcallback(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$(dialogId).ocdialog('close');\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttext: t('core', 'Yes'),\n\t\t\t\t\tclick: function(){\n\t\t\t\t\t\tif (callback !== undefined) {\n\t\t\t\t\t\t\tcallback(true);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$(dialogId).ocdialog('close');\n\t\t\t\t\t},\n\t\t\t\t\tdefaultButton: true\n\t\t\t\t}];\n\t\t\t\tbreak;\n\t\t\tcase OCdialogs.OK_BUTTON:\n\t\t\t\tvar functionToCall = function() {\n\t\t\t\t\t$(dialogId).ocdialog('close');\n\t\t\t\t\tif(callback !== undefined) {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tbuttonlist[0] = {\n\t\t\t\t\ttext: t('core', 'OK'),\n\t\t\t\t\tclick: functionToCall,\n\t\t\t\t\tdefaultButton: true\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$(dialogId).ocdialog({\n\t\t\t\tcloseOnEscape: true,\n\t\t\t\tmodal: modal,\n\t\t\t\tbuttons: buttonlist\n\t\t\t});\n\t\t\tOCdialogs.dialogsCounter++;\n\t\t})\n\t\t.fail(function(status, error) {\n\t\t\t\/\/ If the method is called while navigating away from\n\t\t\t\/\/ the page, we still want to deliver the message.\n\t\t\tif(status === 0) {\n\t\t\t\talert(title + ': ' + content);\n\t\t\t} else {\n\t\t\t\talert(t('core', 'Error loading message template: {error}', {error: error}));\n\t\t\t}\n\t\t});\n\t},\n\t_fileexistsshown: false,\n\t\/**\n\t * Displays file exists dialog\n\t * @param {object} data upload object\n\t * @param {object} original file with name, size and mtime\n\t * @param {object} replacement file with name, size and mtime\n\t * @param {object} controller with onCancel, onSkip, onReplace and onRename methods\n\t * @return {Promise} jquery promise that resolves after the dialog template was loaded\n\t*\/\n\tfileexists:function(data, original, replacement, controller) {\n\t\tvar self = this;\n\t\tvar dialogDeferred = new $.Deferred();\n\n\t\tvar getCroppedPreview = function(file) {\n\t\t\tvar deferred = new $.Deferred();\n\t\t\t\/\/ Only process image files.\n\t\t\tvar type = file.type && file.type.split('\/').shift();\n\t\t\tif (window.FileReader && type === 'image') {\n\t\t\t\tvar reader = new FileReader();\n\t\t\t\treader.onload = function (e) {\n\t\t\t\t\tvar blob = new Blob([e.target.result]);\n\t\t\t\t\twindow.URL = window.URL || window.webkitURL;\n\t\t\t\t\tvar originalUrl = window.URL.createObjectURL(blob);\n\t\t\t\t\tvar image = new Image();\n\t\t\t\t\timage.src = originalUrl;\n\t\t\t\t\timage.onload = function () {\n\t\t\t\t\t\tvar url = crop(image);\n\t\t\t\t\t\tdeferred.resolve(url);\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t\treader.readAsArrayBuffer(file);\n\t\t\t} else {\n\t\t\t\tdeferred.reject();\n\t\t\t}\n\t\t\treturn deferred;\n\t\t};\n\n\t\tvar crop = function(img) {\n\t\t\tvar canvas = document.createElement('canvas'),\n\t\t\t\t\ttargetSize = 96,\n\t\t\t\t\twidth = img.width,\n\t\t\t\t\theight = img.height,\n\t\t\t\t\tx, y, size;\n\n\t\t\t\/\/ Calculate the width and height, constraining the proportions\n\t\t\tif (width > height) {\n\t\t\t\ty = 0;\n\t\t\t\tx = (width - height) \/ 2;\n\t\t\t} else {\n\t\t\t\ty = (height - width) \/ 2;\n\t\t\t\tx = 0;\n\t\t\t}\n\t\t\tsize = Math.min(width, height);\n\n\t\t\t\/\/ Set canvas size to the cropped area\n\t\t\tcanvas.width = size;\n\t\t\tcanvas.height = size;\n\t\t\tvar ctx = canvas.getContext(\"2d\");\n\t\t\tctx.drawImage(img, x, y, size, size, 0, 0, size, size);\n\n\t\t\t\/\/ Resize the canvas to match the destination (right size uses 96px)\n\t\t\tresampleHermite(canvas, size, size, targetSize, targetSize);\n\n\t\t\treturn canvas.toDataURL(\"image\/png\", 0.7);\n\t\t};\n\n\t\t\/**\n\t\t * Fast image resize\/resample using Hermite filter with JavaScript.\n\t\t *\n\t\t * @author: ViliusL\n\t\t *\n\t\t * @param {*} canvas\n\t\t * @param {number} W\n\t\t * @param {number} H\n\t\t * @param {number} W2\n\t\t * @param {number} H2\n\t\t *\/\n\t\tvar resampleHermite = function (canvas, W, H, W2, H2) {\n\t\t\tW2 = Math.round(W2);\n\t\t\tH2 = Math.round(H2);\n\t\t\tvar img = canvas.getContext(\"2d\").getImageData(0, 0, W, H);\n\t\t\tvar img2 = canvas.getContext(\"2d\").getImageData(0, 0, W2, H2);\n\t\t\tvar data = img.data;\n\t\t\tvar data2 = img2.data;\n\t\t\tvar ratio_w = W \/ W2;\n\t\t\tvar ratio_h = H \/ H2;\n\t\t\tvar ratio_w_half = Math.ceil(ratio_w \/ 2);\n\t\t\tvar ratio_h_half = Math.ceil(ratio_h \/ 2);\n\n\t\t\tfor (var j = 0; j < H2; j++) {\n\t\t\t\tfor (var i = 0; i < W2; i++) {\n\t\t\t\t\tvar x2 = (i + j * W2) * 4;\n\t\t\t\t\tvar weight = 0;\n\t\t\t\t\tvar weights = 0;\n\t\t\t\t\tvar weights_alpha = 0;\n\t\t\t\t\tvar gx_r = 0;\n\t\t\t\t\tvar gx_g = 0;\n\t\t\t\t\tvar gx_b = 0;\n\t\t\t\t\tvar gx_a = 0;\n\t\t\t\t\tvar center_y = (j + 0.5) * ratio_h;\n\t\t\t\t\tfor (var yy = Math.floor(j * ratio_h); yy < (j + 1) * ratio_h; yy++) {\n\t\t\t\t\t\tvar dy = Math.abs(center_y - (yy + 0.5)) \/ ratio_h_half;\n\t\t\t\t\t\tvar center_x = (i + 0.5) * ratio_w;\n\t\t\t\t\t\tvar w0 = dy * dy; \/\/pre-calc part of w\n\t\t\t\t\t\tfor (var xx = Math.floor(i * ratio_w); xx < (i + 1) * ratio_w; xx++) {\n\t\t\t\t\t\t\tvar dx = Math.abs(center_x - (xx + 0.5)) \/ ratio_w_half;\n\t\t\t\t\t\t\tvar w = Math.sqrt(w0 + dx * dx);\n\t\t\t\t\t\t\tif (w >= -1 && w <= 1) {\n\t\t\t\t\t\t\t\t\/\/hermite filter\n\t\t\t\t\t\t\t\tweight = 2 * w * w * w - 3 * w * w + 1;\n\t\t\t\t\t\t\t\tif (weight > 0) {\n\t\t\t\t\t\t\t\t\tdx = 4 * (xx + yy * W);\n\t\t\t\t\t\t\t\t\t\/\/alpha\n\t\t\t\t\t\t\t\t\tgx_a += weight * data[dx + 3];\n\t\t\t\t\t\t\t\t\tweights_alpha += weight;\n\t\t\t\t\t\t\t\t\t\/\/colors\n\t\t\t\t\t\t\t\t\tif (data[dx + 3] < 255)\n\t\t\t\t\t\t\t\t\t\tweight = weight * data[dx + 3] \/ 250;\n\t\t\t\t\t\t\t\t\tgx_r += weight * data[dx];\n\t\t\t\t\t\t\t\t\tgx_g += weight * data[dx + 1];\n\t\t\t\t\t\t\t\t\tgx_b += weight * data[dx + 2];\n\t\t\t\t\t\t\t\t\tweights += weight;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdata2[x2] = gx_r \/ weights;\n\t\t\t\t\tdata2[x2 + 1] = gx_g \/ weights;\n\t\t\t\t\tdata2[x2 + 2] = gx_b \/ weights;\n\t\t\t\t\tdata2[x2 + 3] = gx_a \/ weights_alpha;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcanvas.getContext(\"2d\").clearRect(0, 0, Math.max(W, W2), Math.max(H, H2));\n\t\t\tcanvas.width = W2;\n\t\t\tcanvas.height = H2;\n\t\t\tcanvas.getContext(\"2d\").putImageData(img2, 0, 0);\n\t\t};\n\n\t\tvar addConflict = function($conflicts, original, replacement) {\n\n\t\t\tvar $conflict = $conflicts.find('.template').clone().removeClass('template').addClass('conflict');\n\t\t\tvar $originalDiv = $conflict.find('.original');\n\t\t\tvar $replacementDiv = $conflict.find('.replacement');\n\n\t\t\t$conflict.data('data',data);\n\n\t\t\t$conflict.find('.filename').text(original.name);\n\t\t\t$originalDiv.find('.size').text(humanFileSize(original.size));\n\t\t\t$originalDiv.find('.mtime').text(formatDate(original.mtime));\n\t\t\t\/\/ ie sucks\n\t\t\tif (replacement.size && replacement.lastModifiedDate) {\n\t\t\t\t$replacementDiv.find('.size').text(humanFileSize(replacement.size));\n\t\t\t\t$replacementDiv.find('.mtime').text(formatDate(replacement.lastModifiedDate));\n\t\t\t}\n\t\t\tvar path = original.directory + '\/' +original.name;\n\t\t\tvar urlSpec = {\n\t\t\t\tfile:\t\tpath,\n\t\t\t\tx:\t\t96,\n\t\t\t\ty:\t\t96,\n\t\t\t\tc:\t\toriginal.etag,\n\t\t\t\tforceIcon:\t0\n\t\t\t};\n\t\t\tvar previewpath = Files.generatePreviewUrl(urlSpec);\n\t\t\t\/\/ Escaping single quotes\n\t\t\tpreviewpath = previewpath.replace(\/'\/g, \"%27\");\n\t\t\t$originalDiv.find('.icon').css({\"background-image\":   \"url('\" + previewpath + \"')\"});\n\t\t\tgetCroppedPreview(replacement).then(\n\t\t\t\tfunction(path){\n\t\t\t\t\t$replacementDiv.find('.icon').css('background-image','url(' + path + ')');\n\t\t\t\t}, function(){\n\t\t\t\t\tpath = OC.MimeType.getIconUrl(replacement.type);\n\t\t\t\t\t$replacementDiv.find('.icon').css('background-image','url(' + path + ')');\n\t\t\t\t}\n\t\t\t);\n\t\t\t\/\/ connect checkboxes with labels\n\t\t\tvar checkboxId = $conflicts.find('.conflict').length;\n\t\t\t$originalDiv.find('input:checkbox').attr('id', 'checkbox_original_'+checkboxId);\n\t\t\t$replacementDiv.find('input:checkbox').attr('id', 'checkbox_replacement_'+checkboxId);\n\n\t\t\t$conflicts.append($conflict);\n\n\t\t\t\/\/set more recent mtime bold\n\t\t\t\/\/ ie sucks\n\t\t\tif (replacement.lastModifiedDate && replacement.lastModifiedDate.getTime() > original.mtime) {\n\t\t\t\t$replacementDiv.find('.mtime').css('font-weight', 'bold');\n\t\t\t} else if (replacement.lastModifiedDate && replacement.lastModifiedDate.getTime() < original.mtime) {\n\t\t\t\t$originalDiv.find('.mtime').css('font-weight', 'bold');\n\t\t\t} else {\n\t\t\t\t\/\/TODO add to same mtime collection?\n\t\t\t}\n\n\t\t\t\/\/ set bigger size bold\n\t\t\tif (replacement.size && replacement.size > original.size) {\n\t\t\t\t$replacementDiv.find('.size').css('font-weight', 'bold');\n\t\t\t} else if (replacement.size && replacement.size < original.size) {\n\t\t\t\t$originalDiv.find('.size').css('font-weight', 'bold');\n\t\t\t} else {\n\t\t\t\t\/\/TODO add to same size collection?\n\t\t\t}\n\n\t\t\t\/\/TODO show skip action for files with same size and mtime in bottom row\n\n\t\t\t\/\/ always keep readonly files\n\n\t\t\tif (original.status === 'readonly') {\n\t\t\t\t$originalDiv\n\t\t\t\t\t.addClass('readonly')\n\t\t\t\t\t.find('input[type=\"checkbox\"]')\n\t\t\t\t\t\t.prop('checked', true)\n\t\t\t\t\t\t.prop('disabled', true);\n\t\t\t\t$originalDiv.find('.message')\n\t\t\t\t\t.text(t('core','read-only'));\n\t\t\t}\n\t\t};\n\t\t\/\/var selection = controller.getSelection(data.originalFiles);\n\t\t\/\/if (selection.defaultAction) {\n\t\t\/\/\tcontroller[selection.defaultAction](data);\n\t\t\/\/} else {\n\t\tvar dialogName = 'oc-dialog-fileexists-content';\n\t\tvar dialogId = '#' + dialogName;\n\t\tif (this._fileexistsshown) {\n\t\t\t\/\/ add conflict\n\n\t\t\tvar $conflicts = $(dialogId+ ' .conflicts');\n\t\t\taddConflict($conflicts, original, replacement);\n\n\t\t\tvar count = $(dialogId+ ' .conflict').length;\n\t\t\tvar title = n('core',\n\t\t\t\t\t\t\t'{count} file conflict',\n\t\t\t\t\t\t\t'{count} file conflicts',\n\t\t\t\t\t\t\tcount,\n\t\t\t\t\t\t\t{count:count}\n\t\t\t\t\t\t);\n\t\t\t$(dialogId).parent().children('.oc-dialog-title').text(title);\n\n\t\t\t\/\/recalculate dimensions\n\t\t\t$(window).trigger('resize');\n\t\t\tdialogDeferred.resolve();\n\t\t} else {\n\t\t\t\/\/create dialog\n\t\t\tthis._fileexistsshown = true;\n\t\t\t$.when(this._getFileExistsTemplate()).then(function($tmpl) {\n\t\t\t\tvar title = t('core','One file conflict');\n\t\t\t\tvar $dlg = $tmpl.octemplate({\n\t\t\t\t\tdialog_name: dialogName,\n\t\t\t\t\ttitle: title,\n\t\t\t\t\ttype: 'fileexists',\n\n\t\t\t\t\tallnewfiles: t('core','New Files'),\n\t\t\t\t\tallexistingfiles: t('core','Already existing files'),\n\n\t\t\t\t\twhy: t('core','Which files do you want to keep?'),\n\t\t\t\t\twhat: t('core','If you select both versions, the copied file will have a number added to its name.')\n\t\t\t\t});\n\t\t\t\t$('body').append($dlg);\n\n\t\t\t\tif (original && replacement) {\n\t\t\t\t\tvar $conflicts = $dlg.find('.conflicts');\n\t\t\t\t\taddConflict($conflicts, original, replacement);\n\t\t\t\t}\n\n\t\t\t\tvar buttonlist = [{\n\t\t\t\t\t\ttext: t('core', 'Cancel'),\n\t\t\t\t\t\tclasses: 'cancel',\n\t\t\t\t\t\tclick: function(){\n\t\t\t\t\t\t\tif ( typeof controller.onCancel !== 'undefined') {\n\t\t\t\t\t\t\t\tcontroller.onCancel(data);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$(dialogId).ocdialog('close');\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttext: t('core', 'Continue'),\n\t\t\t\t\t\tclasses: 'continue',\n\t\t\t\t\t\tclick: function(){\n\t\t\t\t\t\t\tif ( typeof controller.onContinue !== 'undefined') {\n\t\t\t\t\t\t\t\tcontroller.onContinue($(dialogId + ' .conflict'));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$(dialogId).ocdialog('close');\n\t\t\t\t\t\t}\n\t\t\t\t\t}];\n\n\t\t\t\t$(dialogId).ocdialog({\n\t\t\t\t\twidth: 500,\n\t\t\t\t\tcloseOnEscape: true,\n\t\t\t\t\tmodal: true,\n\t\t\t\t\tbuttons: buttonlist,\n\t\t\t\t\tcloseButton: null,\n\t\t\t\t\tclose: function() {\n\t\t\t\t\t\t\tself._fileexistsshown = false;\n\t\t\t\t\t\t\t$(this).ocdialog('destroy').remove();\n\t\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t$(dialogId).css('height','auto');\n\n\t\t\t\tvar $primaryButton = $dlg.closest('.oc-dialog').find('button.continue');\n\t\t\t\t$primaryButton.prop('disabled', true);\n\n\t\t\t\tfunction updatePrimaryButton() {\n\t\t\t\t\tvar checkedCount = $dlg.find('.conflicts .checkbox:checked').length;\n\t\t\t\t\t$primaryButton.prop('disabled', checkedCount === 0);\n\t\t\t\t}\n\n\t\t\t\t\/\/add checkbox toggling actions\n\t\t\t\t$(dialogId).find('.allnewfiles').on('click', function() {\n\t\t\t\t\tvar $checkboxes = $(dialogId).find('.conflict .replacement input[type=\"checkbox\"]');\n\t\t\t\t\t$checkboxes.prop('checked', $(this).prop('checked'));\n\t\t\t\t});\n\t\t\t\t$(dialogId).find('.allexistingfiles').on('click', function() {\n\t\t\t\t\tvar $checkboxes = $(dialogId).find('.conflict .original:not(.readonly) input[type=\"checkbox\"]');\n\t\t\t\t\t$checkboxes.prop('checked', $(this).prop('checked'));\n\t\t\t\t});\n\t\t\t\t$(dialogId).find('.conflicts').on('click', '.replacement,.original:not(.readonly)', function() {\n\t\t\t\t\tvar $checkbox = $(this).find('input[type=\"checkbox\"]');\n\t\t\t\t\t$checkbox.prop('checked', !$checkbox.prop('checked'));\n\t\t\t\t});\n\t\t\t\t$(dialogId).find('.conflicts').on('click', '.replacement input[type=\"checkbox\"],.original:not(.readonly) input[type=\"checkbox\"]', function() {\n\t\t\t\t\tvar $checkbox = $(this);\n\t\t\t\t\t$checkbox.prop('checked', !$checkbox.prop('checked'));\n\t\t\t\t});\n\n\t\t\t\t\/\/update counters\n\t\t\t\t$(dialogId).on('click', '.replacement,.allnewfiles', function() {\n\t\t\t\t\tvar count = $(dialogId).find('.conflict .replacement input[type=\"checkbox\"]:checked').length;\n\t\t\t\t\tif (count === $(dialogId+ ' .conflict').length) {\n\t\t\t\t\t\t$(dialogId).find('.allnewfiles').prop('checked', true);\n\t\t\t\t\t\t$(dialogId).find('.allnewfiles + .count').text(t('core','(all selected)'));\n\t\t\t\t\t} else if (count > 0) {\n\t\t\t\t\t\t$(dialogId).find('.allnewfiles').prop('checked', false);\n\t\t\t\t\t\t$(dialogId).find('.allnewfiles + .count').text(t('core','({count} selected)',{count:count}));\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$(dialogId).find('.allnewfiles').prop('checked', false);\n\t\t\t\t\t\t$(dialogId).find('.allnewfiles + .count').text('');\n\t\t\t\t\t}\n\t\t\t\t\tupdatePrimaryButton();\n\t\t\t\t});\n\t\t\t\t$(dialogId).on('click', '.original,.allexistingfiles', function(){\n\t\t\t\t\tvar count = $(dialogId).find('.conflict .original input[type=\"checkbox\"]:checked').length;\n\t\t\t\t\tif (count === $(dialogId+ ' .conflict').length) {\n\t\t\t\t\t\t$(dialogId).find('.allexistingfiles').prop('checked', true);\n\t\t\t\t\t\t$(dialogId).find('.allexistingfiles + .count').text(t('core','(all selected)'));\n\t\t\t\t\t} else if (count > 0) {\n\t\t\t\t\t\t$(dialogId).find('.allexistingfiles').prop('checked', false);\n\t\t\t\t\t\t$(dialogId).find('.allexistingfiles + .count')\n\t\t\t\t\t\t\t.text(t('core','({count} selected)',{count:count}));\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$(dialogId).find('.allexistingfiles').prop('checked', false);\n\t\t\t\t\t\t$(dialogId).find('.allexistingfiles + .count').text('');\n\t\t\t\t\t}\n\t\t\t\t\tupdatePrimaryButton();\n\t\t\t\t});\n\n\t\t\t\tdialogDeferred.resolve();\n\t\t\t})\n\t\t\t.fail(function() {\n\t\t\t\tdialogDeferred.reject();\n\t\t\t\talert(t('core', 'Error loading file exists template'));\n\t\t\t});\n\t\t}\n\t\t\/\/}\n\t\treturn dialogDeferred.promise();\n\t},\n\t\/\/ get the gridview setting and set the input accordingly\n\t_getGridSettings: function() {\n\t\tvar self = this;\n\t\t$.get(OC.generateUrl('\/apps\/files\/api\/v1\/showgridview'), function(response) {\n\t\t\tself.$showGridView.get(0).checked = response.gridview;\n\t\t\tself.$showGridView.next('#picker-view-toggle')\n\t\t\t\t.removeClass('icon-toggle-filelist icon-toggle-pictures')\n\t\t\t\t.addClass(response.gridview ? 'icon-toggle-filelist' : 'icon-toggle-pictures')\n\t\t\t$('.list-container').toggleClass('view-grid', response.gridview);\n\t\t});\n\t},\n\t_onGridviewChange: function() {\n\t\tvar show = this.$showGridView.is(':checked');\n\t\t\/\/ only save state if user is logged in\n\t\tif (OC.currentUser) {\n\t\t\t$.post(OC.generateUrl('\/apps\/files\/api\/v1\/showgridview'), {\n\t\t\t\tshow: show\n\t\t\t});\n\t\t}\n\t\tthis.$showGridView.next('#picker-view-toggle')\n\t\t\t.removeClass('icon-toggle-filelist icon-toggle-pictures')\n\t\t\t.addClass(show ? 'icon-toggle-filelist' : 'icon-toggle-pictures')\n\t\t$('.list-container').toggleClass('view-grid', show);\n\t},\n\t_getFilePickerTemplate: function() {\n\t\tvar defer = $.Deferred();\n\t\tif(!this.$filePickerTemplate) {\n\t\t\tvar self = this;\n\t\t\t$.get(OC.filePath('core', 'templates', 'filepicker.html'), function(tmpl) {\n\t\t\t\tself.$filePickerTemplate = $(tmpl);\n\t\t\t\tself.$listTmpl = self.$filePickerTemplate.find('.filelist tbody tr:first-child').detach();\n\t\t\t\tdefer.resolve(self.$filePickerTemplate);\n\t\t\t})\n\t\t\t.fail(function(jqXHR, textStatus, errorThrown) {\n\t\t\t\tdefer.reject(jqXHR.status, errorThrown);\n\t\t\t});\n\t\t} else {\n\t\t\tdefer.resolve(this.$filePickerTemplate);\n\t\t}\n\t\treturn defer.promise();\n\t},\n\t_getMessageTemplate: function() {\n\t\tvar defer = $.Deferred();\n\t\tif(!this.$messageTemplate) {\n\t\t\tvar self = this;\n\t\t\t$.get(OC.filePath('core', 'templates', 'message.html'), function(tmpl) {\n\t\t\t\tself.$messageTemplate = $(tmpl);\n\t\t\t\tdefer.resolve(self.$messageTemplate);\n\t\t\t})\n\t\t\t.fail(function(jqXHR, textStatus, errorThrown) {\n\t\t\t\tdefer.reject(jqXHR.status, errorThrown);\n\t\t\t});\n\t\t} else {\n\t\t\tdefer.resolve(this.$messageTemplate);\n\t\t}\n\t\treturn defer.promise();\n\t},\n\t_getFileExistsTemplate: function () {\n\t\tvar defer = $.Deferred();\n\t\tif (!this.$fileexistsTemplate) {\n\t\t\tvar self = this;\n\t\t\t$.get(OC.filePath('files', 'templates', 'fileexists.html'), function (tmpl) {\n\t\t\t\tself.$fileexistsTemplate = $(tmpl);\n\t\t\t\tdefer.resolve(self.$fileexistsTemplate);\n\t\t\t})\n\t\t\t.fail(function () {\n\t\t\t\tdefer.reject();\n\t\t\t});\n\t\t} else {\n\t\t\tdefer.resolve(this.$fileexistsTemplate);\n\t\t}\n\t\treturn defer.promise();\n\t},\n\t_getFileList: function(dir, mimeType) { \/\/this is only used by the spreedme app atm\n\t\tif (typeof(mimeType) === \"string\") {\n\t\t\tmimeType = [mimeType];\n\t\t}\n\n\t\treturn $.getJSON(\n\t\t\tOC.filePath('files', 'ajax', 'list.php'),\n\t\t\t{\n\t\t\t\tdir: dir,\n\t\t\t\tmimetypes: JSON.stringify(mimeType)\n\t\t\t}\n\t\t);\n\t},\n\n\t\/**\n\t * fills the filepicker with files\n\t*\/\n\t_fillFilePicker:function(dir) {\n\t\tvar self = this;\n\t\tthis.$filelist.empty();\n\t\tthis.$filePicker.find('.emptycontent').hide();\n\t\tthis.$filelistContainer.addClass('icon-loading');\n\t\tthis.$filePicker.data('path', dir);\n\t\tvar filter = this.$filePicker.data('mimetype');\n\t\tif (typeof(filter) === \"string\") {\n\t\t\tfilter = [filter];\n\t\t}\n\t\tself.$fileListHeader.find('.sort-indicator').addClass('hidden').removeClass('icon-triangle-n').removeClass('icon-triangle-s');\n\t\tself.$fileListHeader.find('[data-sort=' + self.filepicker.sortField + '] .sort-indicator').removeClass('hidden');\n\t\tif (self.filepicker.sortOrder === 'asc') {\n\t\t\tself.$fileListHeader.find('[data-sort=' + self.filepicker.sortField + '] .sort-indicator').addClass('icon-triangle-n');\n\t\t} else {\n\t\t\tself.$fileListHeader.find('[data-sort=' + self.filepicker.sortField + '] .sort-indicator').addClass('icon-triangle-s');\n\t\t}\n\t\tself.filepicker.filesClient.getFolderContents(dir).then(function(status, files) {\n\t\t\tif (filter && filter.length > 0 && filter.indexOf('*') === -1) {\n\t\t\t\tfiles = files.filter(function (file) {\n\t\t\t\t\treturn file.type === 'dir' || filter.indexOf(file.mimetype) !== -1;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvar Comparators = {\n\t\t\t\tname: function(fileInfo1, fileInfo2) {\n\t\t\t\t\tif (fileInfo1.type === 'dir' && fileInfo2.type !== 'dir') {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\tif (fileInfo1.type !== 'dir' && fileInfo2.type === 'dir') {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn OC.Util.naturalSortCompare(fileInfo1.name, fileInfo2.name);\n\t\t\t\t},\n\t\t\t\tsize: function(fileInfo1, fileInfo2) {\n\t\t\t\t\treturn fileInfo1.size - fileInfo2.size;\n\t\t\t\t},\n\t\t\t\tmtime: function(fileInfo1, fileInfo2) {\n\t\t\t\t\treturn fileInfo1.mtime - fileInfo2.mtime;\n\t\t\t\t}\n\t\t\t};\n\t\t\tvar comparator = Comparators[self.filepicker.sortField] || Comparators.name;\n\t\t\tfiles = files.sort(function(file1, file2) {\n\t\t\t\tvar isFavorite = function(fileInfo) {\n\t\t\t\t\treturn fileInfo.tags && fileInfo.tags.indexOf(OC.TAG_FAVORITE) >= 0;\n\t\t\t\t};\n\n\t\t\t\tif (isFavorite(file1) && !isFavorite(file2)) {\n\t\t\t\t\treturn -1;\n\t\t\t\t} else if (!isFavorite(file1) && isFavorite(file2)) {\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\n\t\t\t\treturn self.filepicker.sortOrder === 'asc' ? comparator(file1, file2) : -comparator(file1, file2);\n\t\t\t});\n\n\t\t\tself._fillSlug();\n\n\t\t\tif (files.length === 0) {\n\t\t\t\tself.$filePicker.find('.emptycontent').show();\n\t\t\t\tself.$fileListHeader.hide();\n\t\t\t} else {\n\t\t\t\tself.$filePicker.find('.emptycontent').hide();\n\t\t\t\tself.$fileListHeader.show();\n\t\t\t}\n\n\t\t\t$.each(files, function(idx, entry) {\n\t\t\t\tentry.icon = OC.MimeType.getIconUrl(entry.mimetype);\n\t\t\t\tvar simpleSize, sizeColor;\n\t\t\t\tif (typeof(entry.size) !== 'undefined' && entry.size >= 0) {\n\t\t\t\t\tsimpleSize = humanFileSize(parseInt(entry.size, 10), true);\n\t\t\t\t\tsizeColor = Math.round(160 - Math.pow((entry.size \/ (1024 * 1024)), 2));\n\t\t\t\t} else {\n\t\t\t\t\tsimpleSize = t('files', 'Pending');\n\t\t\t\t\tsizeColor = 80;\n\t\t\t\t}\n\t\t\t\tvar $row = self.$listTmpl.octemplate({\n\t\t\t\t\ttype: entry.type,\n\t\t\t\t\tdir: dir,\n\t\t\t\t\tfilename: entry.name,\n\t\t\t\t\tdate: OC.Util.relativeModifiedDate(entry.mtime),\n\t\t\t\t\tsize: simpleSize,\n\t\t\t\t\tsizeColor: sizeColor,\n\t\t\t\t\ticon: entry.icon\n\t\t\t\t});\n\t\t\t\tif (entry.type === 'file') {\n\t\t\t\t\tvar urlSpec = {\n\t\t\t\t\t\tfile: dir + '\/' + entry.name,\n\t\t\t\t\t\tx: 100,\n\t\t\t\t\t\ty: 100\n\t\t\t\t\t};\n\t\t\t\t\tvar img = new Image();\n\t\t\t\t\tvar previewUrl = OC.generateUrl('\/core\/preview.png?') + $.param(urlSpec);\n\t\t\t\t\timg.onload = function() {\n\t\t\t\t\t\tif (img.width > 5) {\n\t\t\t\t\t\t\t$row.find('td.filename').attr('style', 'background-image:url(' + previewUrl + ')');\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\timg.src = previewUrl;\n\t\t\t\t}\n\t\t\t\tself.$filelist.append($row);\n\t\t\t});\n\n\t\t\tself.$filelistContainer.removeClass('icon-loading');\n\t\t});\n\t},\n\t\/**\n\t * fills the tree list with directories\n\t*\/\n\t_fillSlug: function() {\n\t\tthis.$dirTree.empty();\n\t\tvar self = this;\n\t\tvar dir;\n\t\tvar path = this.$filePicker.data('path');\n\t\tvar $template = $('<div data-dir=\"{dir}\"><a>{name}<\/a><\/div>').addClass('crumb');\n\t\tif(path) {\n\t\t\tvar paths = path.split('\/');\n\t\t\t$.each(paths, function(index, dir) {\n\t\t\t\tdir = paths.pop();\n\t\t\t\tif(dir === '') {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tself.$dirTree.prepend($template.octemplate({\n\t\t\t\t\tdir: paths.join('\/') + '\/' + dir,\n\t\t\t\t\tname: dir\n\t\t\t\t}));\n\t\t\t});\n\t\t}\n\t\t$template.octemplate({\n\t\t\tdir: '',\n\t\t\tname: '' \/\/ Ugly but works ;)\n\t\t}, {escapeFunction: null}).prependTo(this.$dirTree);\n\t},\n\t\/**\n\t * handle selection made in the tree list\n\t*\/\n\t_handleTreeListSelect:function(event, type) {\n\t\tvar self = event.data;\n\t\tvar dir = $(event.target).closest('.crumb').data('dir');\n\t\tself._fillFilePicker(dir);\n\t\tvar getOcDialog = (event.target).closest('.oc-dialog');\n\t\tvar buttonEnableDisable = $('.primary', getOcDialog);\n\t\tthis._changeButtonsText(type, dir.split(\/[\/]+\/).pop());\n\t\tif (this.$filePicker.data('mimetype').indexOf(\"httpd\/unix-directory\") !== -1) {\n\t\t\tbuttonEnableDisable.prop(\"disabled\", false);\n\t\t} else {\n\t\t\tbuttonEnableDisable.prop(\"disabled\", true);\n\t\t}\n\t},\n\t\/**\n\t * handle clicks made in the filepicker\n\t*\/\n\t_handlePickerClick:function(event, $element, type) {\n\t\tvar getOcDialog = this.$filePicker.closest('.oc-dialog');\n\t\tvar buttonEnableDisable = getOcDialog.find('.primary');\n\t\tif ($element.data('type') === 'file') {\n\t\t\tif (this.$filePicker.data('multiselect') !== true || !event.ctrlKey) {\n\t\t\t\tthis.$filelist.find('.filepicker_element_selected').removeClass('filepicker_element_selected');\n\t\t\t}\n\t\t\t$element.toggleClass('filepicker_element_selected');\n\t\t\tbuttonEnableDisable.prop(\"disabled\", false);\n\t\t} else if ( $element.data('type') === 'dir' ) {\n\t\t\tthis._fillFilePicker(this.$filePicker.data('path') + '\/' + $element.data('entryname'));\n\t\t\tthis._changeButtonsText(type, $element.data('entryname'));\n\t\t\tif (this.$filePicker.data('mimetype').indexOf(\"httpd\/unix-directory\") !== -1) {\n\t\t\t\tbuttonEnableDisable.prop(\"disabled\", false);\n\t\t\t} else {\n\t\t\t\tbuttonEnableDisable.prop(\"disabled\", true);\n\t\t\t}\n\t\t}\n\t},\n\n\t\/**\n\t * Handle\n\t * @param type of action\n\t * @param dir on which to change buttons text\n\t * @private\n\t *\/\n\t_changeButtonsText: function(type, dir) {\n\t\tvar copyText = dir === '' ? t('core', 'Copy') : t('core', 'Copy to {folder}', {folder: dir});\n\t\tvar moveText = dir === '' ? t('core', 'Move') : t('core', 'Move to {folder}', {folder: dir});\n\t\tvar buttons = $('.oc-dialog-buttonrow button');\n\t\tswitch (type) {\n\t\t\tcase this.FILEPICKER_TYPE_CHOOSE:\n\t\t\t\tbreak;\n\t\t\tcase this.FILEPICKER_TYPE_COPY:\n\t\t\t\tbuttons.text(copyText);\n\t\t\t\tbreak;\n\t\t\tcase this.FILEPICKER_TYPE_MOVE:\n\t\t\t\tbuttons.text(moveText);\n\t\t\t\tbreak;\n\t\t\tcase this.FILEPICKER_TYPE_COPY_MOVE:\n\t\t\t\tbuttons.eq(0).text(copyText);\n\t\t\t\tbuttons.eq(1).text(moveText);\n\t\t\t\tbreak;\n\t\t}\n\t}\n};\n\n\n\/* global oc_isadmin *\/\n\nvar oc_debug;\nvar oc_webroot;\n\nvar oc_current_user = document.getElementsByTagName('head')[0].getAttribute('data-user');\nvar oc_requesttoken = document.getElementsByTagName('head')[0].getAttribute('data-requesttoken');\n\nwindow.oc_config = window.oc_config || {};\n\nif (typeof oc_webroot === \"undefined\") {\n\toc_webroot = location.pathname;\n\tvar pos = oc_webroot.indexOf('\/index.php\/');\n\tif (pos !== -1) {\n\t\toc_webroot = oc_webroot.substr(0, pos);\n\t}\n\telse {\n\t\toc_webroot = oc_webroot.substr(0, oc_webroot.lastIndexOf('\/'));\n\t}\n}\nif (typeof console === \"undefined\" || typeof console.log === \"undefined\") {\n\tif (!window.console) {\n\t\twindow.console = {};\n\t}\n\tvar noOp = function() { };\n\tvar methods = ['log', 'debug', 'warn', 'info', 'error', 'assert', 'time', 'timeEnd'];\n\tfor (var i = 0; i < methods.length; i++) {\n\t\tconsole[methods[i]] = noOp;\n\t}\n}\n\n\/**\n* Sanitizes a HTML string by replacing all potential dangerous characters with HTML entities\n* @param {string} s String to sanitize\n* @return {string} Sanitized string\n*\/\nfunction escapeHTML(s) {\n\treturn s.toString().split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;').split('\"').join('&quot;').split('\\'').join('&#039;');\n}\n\n\/** @namespace OCP *\/\nvar OCP = {},\n\t\/**\n\t * @namespace OC\n\t *\/\n\tOC = {\n\tPERMISSION_NONE:0,\n\tPERMISSION_CREATE:4,\n\tPERMISSION_READ:1,\n\tPERMISSION_UPDATE:2,\n\tPERMISSION_DELETE:8,\n\tPERMISSION_SHARE:16,\n\tPERMISSION_ALL:31,\n\tTAG_FAVORITE: '_$!<Favorite>!$_',\n\t\/* jshint camelcase: false *\/\n\t\/**\n\t * Relative path to Nextcloud root.\n\t * For example: \"\/nextcloud\"\n\t *\n\t * @type string\n\t *\n\t * @deprecated since 8.2, use OC.getRootPath() instead\n\t * @see OC#getRootPath\n\t *\/\n\twebroot:oc_webroot,\n\n\t\/**\n\t * Capabilities\n\t *\n\t * @type array\n\t *\/\n\t_capabilities: window.oc_capabilities || null,\n\n\tappswebroots:(typeof oc_appswebroots !== 'undefined') ? oc_appswebroots:false,\n\t\/**\n\t * Currently logged in user or null if none\n\t *\n\t * @type String\n\t * @deprecated use {@link OC.getCurrentUser} instead\n\t *\/\n\tcurrentUser:(typeof oc_current_user!=='undefined')?oc_current_user:false,\n\tconfig: window.oc_config,\n\tappConfig: window.oc_appconfig || {},\n\ttheme: window.oc_defaults || {},\n\tcoreApps:['', 'admin','log','core\/search','settings','core','3rdparty'],\n\trequestToken: oc_requesttoken,\n\tmenuSpeed: 50,\n\n\t\/**\n\t * Get an absolute url to a file in an app\n\t * @param {string} app the id of the app the file belongs to\n\t * @param {string} file the file path relative to the app folder\n\t * @return {string} Absolute URL to a file\n\t *\/\n\tlinkTo:function(app,file){\n\t\treturn OC.filePath(app,'',file);\n\t},\n\n\t\/**\n\t * Creates a relative url for remote use\n\t * @param {string} service id\n\t * @return {string} the url\n\t *\/\n\tlinkToRemoteBase:function(service) {\n\t\treturn OC.getRootPath() + '\/remote.php\/' + service;\n\t},\n\n\t\/**\n\t * @brief Creates an absolute url for remote use\n\t * @param {string} service id\n\t * @return {string} the url\n\t *\/\n\tlinkToRemote:function(service) {\n\t\treturn window.location.protocol + '\/\/' + window.location.host + OC.linkToRemoteBase(service);\n\t},\n\n\t\/**\n\t * Gets the base path for the given OCS API service.\n\t * @param {string} service name\n\t * @param {int} version OCS API version\n\t * @return {string} OCS API base path\n\t *\/\n\tlinkToOCS: function(service, version) {\n\t\tversion = (version !== 2) ? 1 : 2;\n\t\treturn window.location.protocol + '\/\/' + window.location.host + OC.getRootPath() + '\/ocs\/v' + version + '.php\/' + service + '\/';\n\t},\n\n\t\/**\n\t * Generates the absolute url for the given relative url, which can contain parameters.\n\t * Parameters will be URL encoded automatically.\n\t * @param {string} url\n\t * @param [params] params\n\t * @param [options] options\n\t * @param {bool} [options.escape=true] enable\/disable auto escape of placeholders (by default enabled)\n\t * @return {string} Absolute URL for the given relative URL\n\t *\/\n\tgenerateUrl: function(url, params, options) {\n\t\tvar defaultOptions = {\n\t\t\t\tescape: true\n\t\t\t},\n\t\t\tallOptions = options || {};\n\t\t_.defaults(allOptions, defaultOptions);\n\n\t\tvar _build = function (text, vars) {\n\t\t\tvars = vars || [];\n\t\t\treturn text.replace(\/{([^{}]*)}\/g,\n\t\t\t\tfunction (a, b) {\n\t\t\t\t\tvar r = (vars[b]);\n\t\t\t\t\tif(allOptions.escape) {\n\t\t\t\t\t\treturn (typeof r === 'string' || typeof r === 'number') ? encodeURIComponent(r) : encodeURIComponent(a);\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn (typeof r === 'string' || typeof r === 'number') ? r : a;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\t\t};\n\t\tif (url.charAt(0) !== '\/') {\n\t\t\turl = '\/' + url;\n\n\t\t}\n\n\t\tif(oc_config.modRewriteWorking == true) {\n\t\t\treturn OC.getRootPath() + _build(url, params);\n\t\t}\n\n\t\treturn OC.getRootPath() + '\/index.php' + _build(url, params);\n\t},\n\n\t\/**\n\t * Get the absolute url for a file in an app\n\t * @param {string} app the id of the app\n\t * @param {string} type the type of the file to link to (e.g. css,img,ajax.template)\n\t * @param {string} file the filename\n\t * @return {string} Absolute URL for a file in an app\n\t *\/\n\tfilePath:function(app,type,file){\n\t\tvar isCore=OC.coreApps.indexOf(app)!==-1,\n\t\t\tlink=OC.getRootPath();\n\t\tif(file.substring(file.length-3) === 'php' && !isCore){\n\t\t\tlink+='\/index.php\/apps\/' + app;\n\t\t\tif (file != 'index.php') {\n\t\t\t\tlink+='\/';\n\t\t\t\tif(type){\n\t\t\t\t\tlink+=encodeURI(type + '\/');\n\t\t\t\t}\n\t\t\t\tlink+= file;\n\t\t\t}\n\t\t}else if(file.substring(file.length-3) !== 'php' && !isCore){\n\t\t\tlink=OC.appswebroots[app];\n\t\t\tif(type){\n\t\t\t\tlink+= '\/'+type+'\/';\n\t\t\t}\n\t\t\tif(link.substring(link.length-1) !== '\/'){\n\t\t\t\tlink+='\/';\n\t\t\t}\n\t\t\tlink+=file;\n\t\t}else{\n\t\t\tif ((app == 'settings' || app == 'core' || app == 'search') && type == 'ajax') {\n\t\t\t\tlink+='\/index.php\/';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlink+='\/';\n\t\t\t}\n\t\t\tif(!isCore){\n\t\t\t\tlink+='apps\/';\n\t\t\t}\n\t\t\tif (app !== '') {\n\t\t\t\tapp+='\/';\n\t\t\t\tlink+=app;\n\t\t\t}\n\t\t\tif(type){\n\t\t\t\tlink+=type+'\/';\n\t\t\t}\n\t\t\tlink+=file;\n\t\t}\n\t\treturn link;\n\t},\n\n\t\/**\n\t * Check if a user file is allowed to be handled.\n\t * @param {string} file to check\n\t *\/\n\tfileIsBlacklisted: function(file) {\n\t\treturn !!(file.match(oc_config.blacklist_files_regex));\n\t},\n\n\t\/**\n\t * Redirect to the target URL, can also be used for downloads.\n\t * @param {string} targetURL URL to redirect to\n\t *\/\n\tredirect: function(targetURL) {\n\t\twindow.location = targetURL;\n\t},\n\n\t\/**\n\t * Reloads the current page\n\t *\/\n\treload: function() {\n\t\twindow.location.reload();\n\t},\n\n\t\/**\n\t * Protocol that is used to access this Nextcloud instance\n\t * @return {string} Used protocol\n\t *\/\n\tgetProtocol: function() {\n\t\treturn window.location.protocol.split(':')[0];\n\t},\n\n\t\/**\n\t * Returns the host used to access this Nextcloud instance\n\t * Host is sometimes the same as the hostname but now always.\n\t *\n\t * Examples:\n\t * http:\/\/example.com => example.com\n\t * https:\/\/example.com => example.com\n\t * http:\/\/example.com:8080 => example.com:8080\n\t *\n\t * @return {string} host\n\t *\n\t * @since 8.2\n\t *\/\n\tgetHost: function() {\n\t\treturn window.location.host;\n\t},\n\n\t\/**\n\t * Returns the hostname used to access this Nextcloud instance\n\t * The hostname is always stripped of the port\n\t *\n\t * @return {string} hostname\n\t * @since 9.0\n\t *\/\n\tgetHostName: function() {\n\t\treturn window.location.hostname;\n\t},\n\n\t\/**\n\t * Returns the port number used to access this Nextcloud instance\n\t *\n\t * @return {int} port number\n\t *\n\t * @since 8.2\n\t *\/\n\tgetPort: function() {\n\t\treturn window.location.port;\n\t},\n\n\t\/**\n\t * Returns the web root path where this Nextcloud instance\n\t * is accessible, with a leading slash.\n\t * For example \"\/nextcloud\".\n\t *\n\t * @return {string} web root path\n\t *\n\t * @since 8.2\n\t *\/\n\tgetRootPath: function() {\n\t\treturn OC.webroot;\n\t},\n\n\n\t\/**\n\t * Returns the capabilities\n\t *\n\t * @return {array} capabilities\n\t *\n\t * @since 14.0\n\t *\/\n\tgetCapabilities: function() {\n\t\treturn OC._capabilities;\n\t},\n\n\t\/**\n\t * Returns the currently logged in user or null if there is no logged in\n\t * user (public page mode)\n\t *\n\t * @return {OC.CurrentUser} user spec\n\t * @since 9.0.0\n\t *\/\n\tgetCurrentUser: function() {\n\t\tif (_.isUndefined(this._currentUserDisplayName)) {\n\t\t\tthis._currentUserDisplayName = document.getElementsByTagName('head')[0].getAttribute('data-user-displayname');\n\t\t}\n\t\treturn {\n\t\t\tuid: this.currentUser,\n\t\t\tdisplayName: this._currentUserDisplayName\n\t\t};\n\t},\n\n\t\/**\n\t * get the absolute path to an image file\n\t * if no extension is given for the image, it will automatically decide\n\t * between .png and .svg based on what the browser supports\n\t * @param {string} app the app id to which the image belongs\n\t * @param {string} file the name of the image file\n\t * @return {string}\n\t *\/\n\timagePath:function(app,file){\n\t\tif(file.indexOf('.')==-1){\/\/if no extension is given, use svg\n\t\t\tfile+='.svg';\n\t\t}\n\t\treturn OC.filePath(app,'img',file);\n\t},\n\n\t\/**\n\t * URI-Encodes a file path but keep the path slashes.\n\t *\n\t * @param path path\n\t * @return encoded path\n\t *\/\n\tencodePath: function(path) {\n\t\tif (!path) {\n\t\t\treturn path;\n\t\t}\n\t\tvar parts = path.split('\/');\n\t\tvar result = [];\n\t\tfor (var i = 0; i < parts.length; i++) {\n\t\t\tresult.push(encodeURIComponent(parts[i]));\n\t\t}\n\t\treturn result.join('\/');\n\t},\n\n\t\/**\n\t * Load a script for the server and load it. If the script is already loaded,\n\t * the event handler will be called directly\n\t * @param {string} app the app id to which the script belongs\n\t * @param {string} script the filename of the script\n\t * @param ready event handler to be called when the script is loaded\n\t *\/\n\taddScript:function(app,script,ready){\n\t\tvar deferred, path=OC.filePath(app,'js',script+'.js');\n\t\tif(!OC.addScript.loaded[path]) {\n\t\t\tdeferred = $.Deferred();\n\t\t\t$.getScript(path, function() {\n\t\t\t\tdeferred.resolve();\n\t\t\t});\n\t\t\tOC.addScript.loaded[path] = deferred;\n\t\t} else {\n\t\t\tif (ready) {\n\t\t\t\tready();\n\t\t\t}\n\t\t}\n\t\treturn OC.addScript.loaded[path];\n\t},\n\t\/**\n\t * Loads a CSS file\n\t * @param {string} app the app id to which the css style belongs\n\t * @param {string} style the filename of the css file\n\t *\/\n\taddStyle:function(app,style){\n\t\tvar path=OC.filePath(app,'css',style+'.css');\n\t\tif(OC.addStyle.loaded.indexOf(path)===-1){\n\t\t\tOC.addStyle.loaded.push(path);\n\t\t\tif (document.createStyleSheet) {\n\t\t\t\tdocument.createStyleSheet(path);\n\t\t\t} else {\n\t\t\t\tstyle=$('<link rel=\"stylesheet\" type=\"text\/css\" href=\"'+path+'\"\/>');\n\t\t\t\t$('head').append(style);\n\t\t\t}\n\t\t}\n\t},\n\n\t\/**\n\t * Loads translations for the given app asynchronously.\n\t *\n\t * @param {String} app app name\n\t * @param {Function} callback callback to call after loading\n\t * @return {Promise}\n\t *\/\n\taddTranslations: function(app, callback) {\n\t\treturn OC.L10N.load(app, callback);\n\t},\n\n\t\/**\n\t * Returns the base name of the given path.\n\t * For example for \"\/abc\/somefile.txt\" it will return \"somefile.txt\"\n\t *\n\t * @param {String} path\n\t * @return {String} base name\n\t *\/\n\tbasename: function(path) {\n\t\treturn path.replace(\/\\\\\/g,'\/').replace( \/.*\\\/\/, '' );\n\t},\n\n\t\/**\n\t * Returns the dir name of the given path.\n\t * For example for \"\/abc\/somefile.txt\" it will return \"\/abc\"\n\t *\n\t * @param {String} path\n\t * @return {String} dir name\n\t *\/\n\tdirname: function(path) {\n\t\treturn path.replace(\/\\\\\/g,'\/').replace(\/\\\/[^\\\/]*$\/, '');\n\t},\n\n\t\/**\n\t * Returns whether the given paths are the same, without\n\t * leading, trailing or doubled slashes and also removing\n\t * the dot sections.\n\t *\n\t * @param {String} path1 first path\n\t * @param {String} path2 second path\n\t * @return {bool} true if the paths are the same\n\t *\n\t * @since 9.0\n\t *\/\n\tisSamePath: function(path1, path2) {\n\t\tvar filterDot = function(p) {\n\t\t\treturn p !== '.';\n\t\t};\n\t\tvar pathSections1 = _.filter((path1 || '').split('\/'), filterDot);\n\t\tvar pathSections2 = _.filter((path2 || '').split('\/'), filterDot);\n\t\tpath1 = OC.joinPaths.apply(OC, pathSections1);\n\t\tpath2 = OC.joinPaths.apply(OC, pathSections2);\n\t\treturn path1 === path2;\n\t},\n\n\t\/**\n\t * Join path sections\n\t *\n\t * @param {...String} path sections\n\t *\n\t * @return {String} joined path, any leading or trailing slash\n\t * will be kept\n\t *\n\t * @since 8.2\n\t *\/\n\tjoinPaths: function() {\n\t\tif (arguments.length < 1) {\n\t\t\treturn '';\n\t\t}\n\t\tvar path = '';\n\t\t\/\/ convert to array\n\t\tvar args = Array.prototype.slice.call(arguments);\n\t\t\/\/ discard empty arguments\n\t\targs = _.filter(args, function(arg) {\n\t\t\treturn arg.length > 0;\n\t\t});\n\t\tif (args.length < 1) {\n\t\t\treturn '';\n\t\t}\n\n\t\tvar lastArg = args[args.length - 1];\n\t\tvar leadingSlash = args[0].charAt(0) === '\/';\n\t\tvar trailingSlash = lastArg.charAt(lastArg.length - 1) === '\/';\n\t\tvar sections = [];\n\t\tvar i;\n\t\tfor (i = 0; i < args.length; i++) {\n\t\t\tsections = sections.concat(args[i].split('\/'));\n\t\t}\n\t\tvar first = !leadingSlash;\n\t\tfor (i = 0; i < sections.length; i++) {\n\t\t\tif (sections[i] !== '') {\n\t\t\t\tif (first) {\n\t\t\t\t\tfirst = false;\n\t\t\t\t} else {\n\t\t\t\t\tpath += '\/';\n\t\t\t\t}\n\t\t\t\tpath += sections[i];\n\t\t\t}\n\t\t}\n\n\t\tif (trailingSlash) {\n\t\t\t\/\/ add it back\n\t\t\tpath += '\/';\n\t\t}\n\t\treturn path;\n\t},\n\n\t\/**\n\t * Do a search query and display the results\n\t * @param {string} query the search query\n\t *\/\n\tsearch: function (query) {\n\t\tOC.Search.search(query, null, 0, 30);\n\t},\n\t\/**\n\t * Dialog helper for jquery dialogs.\n\t *\n\t * @namespace OC.dialogs\n\t *\/\n\tdialogs:OCdialogs,\n\t\/**\n\t * Parses a URL query string into a JS map\n\t * @param {string} queryString query string in the format param1=1234&param2=abcde&param3=xyz\n\t * @return {Object.<string, string>} map containing key\/values matching the URL parameters\n\t *\/\n\tparseQueryString:function(queryString){\n\t\tvar parts,\n\t\t\tpos,\n\t\t\tcomponents,\n\t\t\tresult = {},\n\t\t\tkey,\n\t\t\tvalue;\n\t\tif (!queryString){\n\t\t\treturn null;\n\t\t}\n\t\tpos = queryString.indexOf('?');\n\t\tif (pos >= 0){\n\t\t\tqueryString = queryString.substr(pos + 1);\n\t\t}\n\t\tparts = queryString.replace(\/\\+\/g, '%20').split('&');\n\t\tfor (var i = 0; i < parts.length; i++){\n\t\t\t\/\/ split on first equal sign\n\t\t\tvar part = parts[i];\n\t\t\tpos = part.indexOf('=');\n\t\t\tif (pos >= 0) {\n\t\t\t\tcomponents = [\n\t\t\t\t\tpart.substr(0, pos),\n\t\t\t\t\tpart.substr(pos + 1)\n\t\t\t\t];\n\t\t\t}\n\t\t\telse {\n\t\t\t\t\/\/ key only\n\t\t\t\tcomponents = [part];\n\t\t\t}\n\t\t\tif (!components.length){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tkey = decodeURIComponent(components[0]);\n\t\t\tif (!key){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\/\/ if equal sign was there, return string\n\t\t\tif (components.length > 1) {\n\t\t\t\tresult[key] = decodeURIComponent(components[1]);\n\t\t\t}\n\t\t\t\/\/ no equal sign => null value\n\t\t\telse {\n\t\t\t\tresult[key] = null;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t},\n\n\t\/**\n\t * Builds a URL query from a JS map.\n\t * @param {Object.<string, string>} params map containing key\/values matching the URL parameters\n\t * @return {string} String containing a URL query (without question) mark\n\t *\/\n\tbuildQueryString: function(params) {\n\t\tif (!params) {\n\t\t\treturn '';\n\t\t}\n\t\treturn $.map(params, function(value, key) {\n\t\t\tvar s = encodeURIComponent(key);\n\t\t\tif (value !== null && typeof(value) !== 'undefined') {\n\t\t\t\ts += '=' + encodeURIComponent(value);\n\t\t\t}\n\t\t\treturn s;\n\t\t}).join('&');\n\t},\n\n\t\/**\n\t * Opens a popup with the setting for an app.\n\t * @param {string} appid The ID of the app e.g. 'calendar', 'contacts' or 'files'.\n\t * @param {boolean|string}\u00a0loadJS If true 'js\/settings.js' is loaded. If it's a string\n\t * it will attempt to load a script by that name in the 'js' directory.\n\t * @param {boolean} [cache] If true the javascript file won't be forced refreshed. Defaults to true.\n\t * @param {string} [scriptName] The name of the PHP file to load. Defaults to 'settings.php' in\n\t * the root of the app directory hierarchy.\n\t *\/\n\tappSettings:function(args) {\n\t\tif(typeof args === 'undefined' || typeof args.appid === 'undefined') {\n\t\t\tthrow { name: 'MissingParameter', message: 'The parameter appid is missing' };\n\t\t}\n\t\tvar props = {scriptName:'settings.php', cache:true};\n\t\t$.extend(props, args);\n\t\tvar settings = $('#appsettings');\n\t\tif(settings.length === 0) {\n\t\t\tthrow { name: 'MissingDOMElement', message: 'There has be be an element with id \"appsettings\" for the popup to show.' };\n\t\t}\n\t\tvar popup = $('#appsettings_popup');\n\t\tif(popup.length === 0) {\n\t\t\t$('body').prepend('<div class=\"popup hidden\" id=\"appsettings_popup\"><\/div>');\n\t\t\tpopup = $('#appsettings_popup');\n\t\t\tpopup.addClass(settings.hasClass('topright') ? 'topright' : 'bottomleft');\n\t\t}\n\t\tif(popup.is(':visible')) {\n\t\t\tpopup.hide().remove();\n\t\t} else {\n\t\t\tvar arrowclass = settings.hasClass('topright') ? 'up' : 'left';\n\t\t\tvar jqxhr = $.get(OC.filePath(props.appid, '', props.scriptName), function(data) {\n\t\t\t\tpopup.html(data).ready(function() {\n\t\t\t\t\tpopup.prepend('<span class=\"arrow '+arrowclass+'\"><\/span><h2>'+t('core', 'Settings')+'<\/h2><a class=\"close\"><\/a>').show();\n\t\t\t\t\tpopup.find('.close').bind('click', function() {\n\t\t\t\t\t\tpopup.remove();\n\t\t\t\t\t});\n\t\t\t\t\tif(typeof props.loadJS !== 'undefined') {\n\t\t\t\t\t\tvar scriptname;\n\t\t\t\t\t\tif(props.loadJS === true) {\n\t\t\t\t\t\t\tscriptname = 'settings.js';\n\t\t\t\t\t\t} else if(typeof props.loadJS === 'string') {\n\t\t\t\t\t\t\tscriptname = props.loadJS;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow { name: 'InvalidParameter', message: 'The \"loadJS\" parameter must be either boolean or a string.' };\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(props.cache) {\n\t\t\t\t\t\t\t$.ajaxSetup({cache: true});\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$.getScript(OC.filePath(props.appid, 'js', scriptname))\n\t\t\t\t\t\t.fail(function(jqxhr, settings, e) {\n\t\t\t\t\t\t\tthrow e;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}).show();\n\t\t\t}, 'html');\n\t\t}\n\t},\n\n\t\/**\n\t * For menu toggling\n\t * @todo Write documentation\n\t *\n\t * @param {jQuery} $toggle\n\t * @param {jQuery} $menuEl\n\t * @param {function|undefined} toggle callback invoked everytime the menu is opened\n\t * @param {boolean} headerMenu is this a top right header menu?\n\t * @returns {undefined}\n\t *\/\n\tregisterMenu: function($toggle, $menuEl, toggle, headerMenu) {\n\t\tvar self = this;\n\t\t$menuEl.addClass('menu');\n\n\t\t\/\/ On link, the enter key trigger a click event\n\t\t\/\/ Only use the click to avoid two fired events\n\t\t$toggle.on($toggle.prop('tagName') === 'A'\n\t\t\t? 'click.menu'\n\t\t\t: 'click.menu keyup.menu', function(event) {\n\t\t\t\/\/ prevent the link event (append anchor to URL)\n\t\t\tevent.preventDefault();\n\n\t\t\t\/\/ allow enter key as a trigger\n\t\t\tif (event.key && event.key !== \"Enter\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ($menuEl.is(OC._currentMenu)) {\n\t\t\t\tself.hideMenus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\/\/ another menu was open?\n\t\t\telse if (OC._currentMenu) {\n\t\t\t\t\/\/ close it\n\t\t\t\tself.hideMenus();\n\t\t\t}\n\n\t\t\tif (headerMenu === true) {\n\t\t\t\t$menuEl.parent().addClass('openedMenu');\n\t\t\t}\n\n\t\t\t\/\/ Set menu to expanded\n\t\t\t$toggle.attr('aria-expanded', true);\n\n\t\t\t$menuEl.slideToggle(OC.menuSpeed, toggle);\n\t\t\tOC._currentMenu = $menuEl;\n\t\t\tOC._currentMenuToggle = $toggle;\n\t\t});\n\t},\n\n\t\/**\n\t *  @todo Write documentation\n\t *\/\n\tunregisterMenu: function($toggle, $menuEl) {\n\t\t\/\/ close menu if opened\n\t\tif ($menuEl.is(OC._currentMenu)) {\n\t\t\tthis.hideMenus();\n\t\t}\n\t\t$toggle.off('click.menu').removeClass('menutoggle');\n\t\t$menuEl.removeClass('menu');\n\t},\n\n\t\/**\n\t * Hides any open menus\n\t *\n\t * @param {Function} complete callback when the hiding animation is done\n\t *\/\n\thideMenus: function(complete) {\n\t\tif (OC._currentMenu) {\n\t\t\tvar lastMenu = OC._currentMenu;\n\t\t\tOC._currentMenu.trigger(new $.Event('beforeHide'));\n\t\t\tOC._currentMenu.slideUp(OC.menuSpeed, function() {\n\t\t\t\tlastMenu.trigger(new $.Event('afterHide'));\n\t\t\t\tif (complete) {\n\t\t\t\t\tcomplete.apply(this, arguments);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t\/\/ Set menu to closed\n\t\t$('.menutoggle').attr('aria-expanded', false);\n\n\t\t$('.openedMenu').removeClass('openedMenu');\n\t\tOC._currentMenu = null;\n\t\tOC._currentMenuToggle = null;\n\t},\n\n\t\/**\n\t * Shows a given element as menu\n\t *\n\t * @param {Object} [$toggle=null] menu toggle\n\t * @param {Object} $menuEl menu element\n\t * @param {Function} complete callback when the showing animation is done\n\t *\/\n\tshowMenu: function($toggle, $menuEl, complete) {\n\t\tif ($menuEl.is(OC._currentMenu)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.hideMenus();\n\t\tOC._currentMenu = $menuEl;\n\t\tOC._currentMenuToggle = $toggle;\n\t\t$menuEl.trigger(new $.Event('beforeShow'));\n\t\t$menuEl.show();\n\t\t$menuEl.trigger(new $.Event('afterShow'));\n\t\t\/\/ no animation\n\t\tif (_.isFunction(complete)) {\n\t\t\tcomplete();\n\t\t}\n\t},\n\n\t\/**\n\t * Wrapper for matchMedia\n\t *\n\t * This is makes it possible for unit tests to\n\t * stub matchMedia (which doesn't work in PhantomJS)\n\t * @private\n\t *\/\n\t_matchMedia: function(media) {\n\t\tif (window.matchMedia) {\n\t\t\treturn window.matchMedia(media);\n\t\t}\n\t\treturn false;\n\t},\n\n\t\/**\n\t * Returns the user's locale as a BCP 47 compliant language tag\n\t *\n\t * @return {String} locale string\n\t *\/\n\tgetCanonicalLocale: function() {\n\t\tvar locale = this.getLocale();\n\t\treturn typeof locale === 'string' ? locale.replace(\/_\/g, '-') : locale;\n\t},\n\n\t\/**\n\t * Returns the user's locale\n\t *\n\t * @return {String} locale string\n\t *\/\n\tgetLocale: function() {\n\t\treturn $('html').data('locale');\n\t},\n\n\t\/**\n\t * Returns the user's language\n\t *\n\t * @returns {String} language string\n\t *\/\n\tgetLanguage: function () {\n\t\treturn $('html').prop('lang');\n\t},\n\n\t\/**\n\t * Returns whether the current user is an administrator\n\t *\n\t * @return {bool} true if the user is an admin, false otherwise\n\t * @since 9.0.0\n\t *\/\n\tisUserAdmin: function() {\n\t\treturn oc_isadmin;\n\t},\n\n\t\/**\n\t * Warn users that the connection to the server was lost temporarily\n\t *\n\t * This function is throttled to prevent stacked notfications.\n\t * After 7sec the first notification is gone, then we can show another one\n\t * if necessary.\n\t *\/\n\t_ajaxConnectionLostHandler: _.throttle(function() {\n\t\tOC.Notification.showTemporary(t('core', 'Connection to server lost'));\n\t}, 7 * 1000, {trailing: false}),\n\n\t\/**\n\t * Process ajax error, redirects to main page\n\t * if an error\/auth error status was returned.\n\t *\/\n\t_processAjaxError: function(xhr) {\n\t\tvar self = this;\n\t\t\/\/ purposefully aborted request ?\n\t\t\/\/ this._userIsNavigatingAway needed to distinguish ajax calls cancelled by navigating away\n\t\t\/\/ from calls cancelled by failed cross-domain ajax due to SSO redirect\n\t\tif (xhr.status === 0 && (xhr.statusText === 'abort' || xhr.statusText === 'timeout' || self._reloadCalled)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (_.contains([302, 303, 307, 401], xhr.status) && OC.currentUser) {\n\t\t\t\/\/ sometimes \"beforeunload\" happens later, so need to defer the reload a bit\n\t\t\tsetTimeout(function() {\n\t\t\t\tif (!self._userIsNavigatingAway && !self._reloadCalled) {\n\t\t\t\t\tvar timer = 0;\n\t\t\t\t\tvar seconds = 5;\n\t\t\t\t\tvar interval = setInterval( function() {\n\t\t\t\t\t\tOC.Notification.showUpdate(n('core', 'Problem loading page, reloading in %n second', 'Problem loading page, reloading in %n seconds', seconds - timer));\n\t\t\t\t\t\tif (timer >= seconds) {\n\t\t\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\t\t\tOC.reload();\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttimer++;\n\t\t\t\t\t\t}, 1000 \/\/ 1 second interval\n\t\t\t\t\t);\n\n\t\t\t\t\t\/\/ only call reload once\n\t\t\t\t\tself._reloadCalled = true;\n\t\t\t\t}\n\t\t\t}, 100);\n\t\t} else if(xhr.status === 0) {\n\t\t\t\/\/ Connection lost (e.g. WiFi disconnected or server is down)\n\t\t\tsetTimeout(function() {\n\t\t\t\tif (!self._userIsNavigatingAway && !self._reloadCalled) {\n\t\t\t\t\tself._ajaxConnectionLostHandler();\n\t\t\t\t}\n\t\t\t}, 100);\n\t\t}\n\t},\n\n\t\/**\n\t * Registers XmlHttpRequest object for global error processing.\n\t *\n\t * This means that if this XHR object returns 401 or session timeout errors,\n\t * the current page will automatically be reloaded.\n\t *\n\t * @param {XMLHttpRequest} xhr\n\t *\/\n\tregisterXHRForErrorProcessing: function(xhr) {\n\t\tvar loadCallback = function() {\n\t\t\tif (xhr.readyState !== 4) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t\/\/ fire jquery global ajax error handler\n\t\t\t$(document).trigger(new $.Event('ajaxError'), xhr);\n\t\t};\n\n\t\tvar errorCallback = function() {\n\t\t\t\/\/ fire jquery global ajax error handler\n\t\t\t$(document).trigger(new $.Event('ajaxError'), xhr);\n\t\t};\n\n\t\tif (xhr.addEventListener) {\n\t\t\txhr.addEventListener('load', loadCallback);\n\t\t\txhr.addEventListener('error', errorCallback);\n\t\t}\n\n\t}\n};\n\n\/**\n * Current user attributes\n *\n * @typedef {Object} OC.CurrentUser\n *\n * @property {String} uid user id\n * @property {String} displayName display name\n *\/\n\n\/**\n * @namespace OC.Plugins\n *\/\nOC.Plugins = {\n\t\/**\n\t * @type Array.<OC.Plugin>\n\t *\/\n\t_plugins: {},\n\n\t\/**\n\t * Register plugin\n\t *\n\t * @param {String} targetName app name \/ class name to hook into\n\t * @param {OC.Plugin} plugin\n\t *\/\n\tregister: function(targetName, plugin) {\n\t\tvar plugins = this._plugins[targetName];\n\t\tif (!plugins) {\n\t\t\tplugins = this._plugins[targetName] = [];\n\t\t}\n\t\tplugins.push(plugin);\n\t},\n\n\t\/**\n\t * Returns all plugin registered to the given target\n\t * name \/ app name \/ class name.\n\t *\n\t * @param {String} targetName app name \/ class name to hook into\n\t * @return {Array.<OC.Plugin>} array of plugins\n\t *\/\n\tgetPlugins: function(targetName) {\n\t\treturn this._plugins[targetName] || [];\n\t},\n\n\t\/**\n\t * Call attach() on all plugins registered to the given target name.\n\t *\n\t * @param {String} targetName app name \/ class name\n\t * @param {Object} object to be extended\n\t * @param {Object} [options] options\n\t *\/\n\tattach: function(targetName, targetObject, options) {\n\t\tvar plugins = this.getPlugins(targetName);\n\t\tfor (var i = 0; i < plugins.length; i++) {\n\t\t\tif (plugins[i].attach) {\n\t\t\t\tplugins[i].attach(targetObject, options);\n\t\t\t}\n\t\t}\n\t},\n\n\t\/**\n\t * Call detach() on all plugins registered to the given target name.\n\t *\n\t * @param {String} targetName app name \/ class name\n\t * @param {Object} object to be extended\n\t * @param {Object} [options] options\n\t *\/\n\tdetach: function(targetName, targetObject, options) {\n\t\tvar plugins = this.getPlugins(targetName);\n\t\tfor (var i = 0; i < plugins.length; i++) {\n\t\t\tif (plugins[i].detach) {\n\t\t\t\tplugins[i].detach(targetObject, options);\n\t\t\t}\n\t\t}\n\t},\n\n\t\/**\n\t * Plugin\n\t *\n\t * @todo make this a real class in the future\n\t * @typedef {Object} OC.Plugin\n\t *\n\t * @property {String} name plugin name\n\t * @property {Function} attach function that will be called when the\n\t * plugin is attached\n\t * @property {Function} [detach] function that will be called when the\n\t * plugin is detached\n\t *\/\n\n};\n\n\/**\n * @namespace OC.search\n *\/\nOC.search.customResults = {};\n\/**\n * @deprecated use get\/setFormatter() instead\n *\/\nOC.search.resultTypes = {};\n\nOC.addStyle.loaded=[];\nOC.addScript.loaded=[];\n\n\/**\n * A little class to manage a status field for a \"saving\" process.\n * It can be used to display a starting message (e.g. \"Saving...\") and then\n * replace it with a green success message or a red error message.\n *\n * @namespace OC.msg\n *\/\nOC.msg = {\n\t\/**\n\t * Displayes a \"Saving...\" message in the given message placeholder\n\t *\n\t * @param {Object} selector\tPlaceholder to display the message in\n\t *\/\n\tstartSaving: function(selector) {\n\t\tthis.startAction(selector, t('core', 'Saving...'));\n\t},\n\n\t\/**\n\t * Displayes a custom message in the given message placeholder\n\t *\n\t * @param {Object} selector\tPlaceholder to display the message in\n\t * @param {string} message\tPlain text message to display (no HTML allowed)\n\t *\/\n\tstartAction: function(selector, message) {\n\t\t$(selector).text(message)\n\t\t\t.removeClass('success')\n\t\t\t.removeClass('error')\n\t\t\t.stop(true, true)\n\t\t\t.show();\n\t},\n\n\t\/**\n\t * Displayes an success\/error message in the given selector\n\t *\n\t * @param {Object} selector\tPlaceholder to display the message in\n\t * @param {Object} response\tResponse of the server\n\t * @param {Object} response.data\tData of the servers response\n\t * @param {string} response.data.message\tPlain text message to display (no HTML allowed)\n\t * @param {string} response.status\tis being used to decide whether the message\n\t * is displayed as an error\/success\n\t *\/\n\tfinishedSaving: function(selector, response) {\n\t\tthis.finishedAction(selector, response);\n\t},\n\n\t\/**\n\t * Displayes an success\/error message in the given selector\n\t *\n\t * @param {Object} selector\tPlaceholder to display the message in\n\t * @param {Object} response\tResponse of the server\n\t * @param {Object} response.data Data of the servers response\n\t * @param {string} response.data.message Plain text message to display (no HTML allowed)\n\t * @param {string} response.status is being used to decide whether the message\n\t * is displayed as an error\/success\n\t *\/\n\tfinishedAction: function(selector, response) {\n\t\tif (response.status === \"success\") {\n\t\t\tthis.finishedSuccess(selector, response.data.message);\n\t\t} else {\n\t\t\tthis.finishedError(selector, response.data.message);\n\t\t}\n\t},\n\n\t\/**\n\t * Displayes an success message in the given selector\n\t *\n\t * @param {Object} selector Placeholder to display the message in\n\t * @param {string} message Plain text success message to display (no HTML allowed)\n\t *\/\n\tfinishedSuccess: function(selector, message) {\n\t\t$(selector).text(message)\n\t\t\t.addClass('success')\n\t\t\t.removeClass('error')\n\t\t\t.stop(true, true)\n\t\t\t.delay(3000)\n\t\t\t.fadeOut(900)\n\t\t\t.show();\n\t},\n\n\t\/**\n\t * Displayes an error message in the given selector\n\t *\n\t * @param {Object} selector Placeholder to display the message in\n\t * @param {string} message Plain text error message to display (no HTML allowed)\n\t *\/\n\tfinishedError: function(selector, message) {\n\t\t$(selector).text(message)\n\t\t\t.addClass('error')\n\t\t\t.removeClass('success')\n\t\t\t.show();\n\t}\n};\n\n\/**\n * @todo Write documentation\n * @namespace\n *\/\nOC.Notification={\n\tqueuedNotifications: [],\n\tgetDefaultNotificationFunction: null,\n\n\t\/**\n\t * @type Array<int>\n\t * @description array of notification timers\n\t *\/\n\tnotificationTimers: [],\n\n\t\/**\n\t * @param callback\n\t * @todo Write documentation\n\t *\/\n\tsetDefault: function(callback) {\n\t\tOC.Notification.getDefaultNotificationFunction = callback;\n\t},\n\n\t\/**\n\t * Hides a notification.\n\t *\n\t * If a row is given, only hide that one.\n\t * If no row is given, hide all notifications.\n\t *\n\t * @param {jQuery} [$row] notification row\n\t * @param {Function} [callback] callback\n\t *\/\n\thide: function($row, callback) {\n\t\tvar self = this;\n\t\tvar $notification = $('#notification');\n\n\t\tif (_.isFunction($row)) {\n\t\t\t\/\/ first arg is the callback\n\t\t\tcallback = $row;\n\t\t\t$row = undefined;\n\t\t}\n\n\t\tif (!$row) {\n\t\t\tconsole.warn('Missing argument $row in OC.Notification.hide() call, caller needs to be adjusted to only dismiss its own notification');\n\t\t\t\/\/ assume that the row to be hidden is the first one\n\t\t\t$row = $notification.find('.row:first');\n\t\t}\n\n\t\tif ($row && $notification.find('.row').length > 1) {\n\t\t\t\/\/ remove the row directly\n\t\t\t$row.remove();\n\t\t\tif (callback) {\n\t\t\t\tcallback.call();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t_.defer(function() {\n\t\t\t\/\/ fade out is supposed to only fade when there is a single row\n\t\t\t\/\/ however, some code might call hide() and show() directly after,\n\t\t\t\/\/ which results in more than one element\n\t\t\t\/\/ in this case, simply delete that one element that was supposed to\n\t\t\t\/\/ fade out\n\t\t\t\/\/\n\t\t\t\/\/ FIXME: remove once all callers are adjusted to only hide their own notifications\n\t\t\tif ($notification.find('.row').length > 1) {\n\t\t\t\t$row.remove();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t\/\/ else, fade out whatever was present\n\t\t\t$notification.fadeOut('400', function(){\n\t\t\t\tif (self.isHidden()) {\n\t\t\t\t\tif (self.getDefaultNotificationFunction) {\n\t\t\t\t\t\tself.getDefaultNotificationFunction.call();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (callback) {\n\t\t\t\t\tcallback.call();\n\t\t\t\t}\n\t\t\t\t$notification.empty();\n\t\t\t});\n\t\t});\n\t},\n\n\t\/**\n\t * Shows a notification as HTML without being sanitized before.\n\t * If you pass unsanitized user input this may lead to a XSS vulnerability.\n\t * Consider using show() instead of showHTML()\n\t *\n\t * @param {string} html Message to display\n\t * @param {Object} [options] options\n\t * @param {string} [options.type] notification type\n\t * @param {int} [options.timeout=0] timeout value, defaults to 0 (permanent)\n\t * @return {jQuery} jQuery element for notification row\n\t *\/\n\tshowHtml: function(html, options) {\n\t\toptions = options || {};\n\t\t_.defaults(options, {\n\t\t\ttimeout: 0\n\t\t});\n\n\t\tvar self = this;\n\t\tvar $notification = $('#notification');\n\t\tif (this.isHidden()) {\n\t\t\t$notification.fadeIn().css('display','inline-block');\n\t\t}\n\t\tvar $row = $('<div class=\"row\"><\/div>');\n\t\tif (options.type) {\n\t\t\t$row.addClass('type-' + options.type);\n\t\t}\n\t\tif (options.type === 'error') {\n\t\t\t\/\/ add a close button\n\t\t\tvar $closeButton = $('<a class=\"action close icon-close\" href=\"#\"><\/a>');\n\t\t\t$closeButton.attr('alt', t('core', 'Dismiss'));\n\t\t\t$row.append($closeButton);\n\t\t\t$closeButton.one('click', function() {\n\t\t\t\tself.hide($row);\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\t$row.addClass('closeable');\n\t\t}\n\n\t\t$row.prepend(html);\n\t\t$notification.append($row);\n\n\t\tif(options.timeout > 0) {\n\t\t\t\/\/ register timeout to vanish notification\n\t\t\tthis.notificationTimers.push(setTimeout(function() {\n\t\t\t\tself.hide($row);\n\t\t\t}, (options.timeout * 1000)));\n\t\t}\n\n\t\treturn $row;\n\t},\n\n\t\/**\n\t * Shows a sanitized notification\n\t *\n\t * @param {string} text Message to display\n\t * @param {Object} [options] options\n\t * @param {string} [options.type] notification type\n\t * @param {int} [options.timeout=0] timeout value, defaults to 0 (permanent)\n\t * @return {jQuery} jQuery element for notification row\n\t *\/\n\tshow: function(text, options) {\n\t\treturn this.showHtml($('<div\/>').text(text).html(), options);\n\t},\n\n\t\/**\n\t * Updates (replaces) a sanitized notification.\n\t *\n\t * @param {string} text Message to display\n\t * @return {jQuery} JQuery element for notificaiton row\n\t *\/\n\tshowUpdate: function(text) {\n\t\tvar $notification = $('#notification');\n\t\t\/\/ sanitise\n\t\tvar $html = $('<div\/>').text(text).html();\n\n\t\t\/\/ new notification\n\t\tif (text && $notification.find('.row').length == 0) {\n\t\t\treturn this.showHtml($html);\n\t\t}\n\n\t\tvar $row = $('<div class=\"row\"><\/div>').prepend($html);\n\n\t\t\/\/ just update html in notification\n\t\t$notification.html($row);\n\n\t\treturn $row;\n\t},\n\n\t\/**\n\t * Shows a notification that disappears after x seconds, default is\n\t * 7 seconds\n\t *\n\t * @param {string} text Message to show\n\t * @param {array} [options] options array\n\t * @param {int} [options.timeout=7] timeout in seconds, if this is 0 it will show the message permanently\n\t * @param {boolean} [options.isHTML=false] an indicator for HTML notifications (true) or text (false)\n\t * @param {string} [options.type] notification type\n\t *\/\n\tshowTemporary: function(text, options) {\n\t\tvar defaults = {\n\t\t\tisHTML: false,\n\t\t\ttimeout: 7\n\t\t};\n\t\toptions = options || {};\n\t\t\/\/ merge defaults with passed in options\n\t\t_.defaults(options, defaults);\n\n\t\tvar $row;\n\t\tif(options.isHTML) {\n\t\t\t$row = this.showHtml(text, options);\n\t\t} else {\n\t\t\t$row = this.show(text, options);\n\t\t}\n\t\treturn $row;\n\t},\n\n\t\/**\n\t * Returns whether a notification is hidden.\n\t * @return {boolean}\n\t *\/\n\tisHidden: function() {\n\t\treturn !$(\"#notification\").find('.row').length;\n\t}\n};\n\n\/**\n * Initializes core\n *\/\nfunction initCore() {\n\t\/**\n\t * Disable automatic evaluation of responses for $.ajax() functions (and its\n\t * higher-level alternatives like $.get() and $.post()).\n\t *\n\t * If a response to a $.ajax() request returns a content type of \"application\/javascript\"\n\t * JQuery would previously execute the response body. This is a pretty unexpected\n\t * behaviour and can result in a bypass of our Content-Security-Policy as well as\n\t * multiple unexpected XSS vectors.\n\t *\/\n\t$.ajaxSetup({\n\t\tcontents: {\n\t\t\tscript: false\n\t\t}\n\t});\n\n\t\/**\n\t * Disable execution of eval in jQuery. We do require an allowed eval CSP\n\t * configuration at the moment for handlebars et al. But for jQuery there is\n\t * not much of a reason to execute JavaScript directly via eval.\n\t *\n\t * This thus mitigates some unexpected XSS vectors.\n\t *\/\n\tjQuery.globalEval = function(){};\n\n\t\/**\n\t * Set users locale to moment.js as soon as possible\n\t *\/\n\tmoment.locale(OC.getLocale());\n\n\tvar userAgent = window.navigator.userAgent;\n\tvar msie = userAgent.indexOf('MSIE ');\n\tvar trident = userAgent.indexOf('Trident\/');\n\tvar edge = userAgent.indexOf('Edge\/');\n\n\tif (msie > 0 || trident > 0) {\n\t\t\/\/ (IE 10 or older) || IE 11\n\t\t$('html').addClass('ie');\n\t} else if (edge > 0) {\n\t\t\/\/ for edge\n\t\t$('html').addClass('edge');\n\t}\n\n\t\/\/ css variables fallback for IE\n\tif (msie > 0 || trident > 0) {\n\t\tcssVars();\n\t}\n\n\t$(window).on('unload.main', function() {\n\t\tOC._unloadCalled = true;\n\t});\n\t$(window).on('beforeunload.main', function() {\n\t\t\/\/ super-trick thanks to http:\/\/stackoverflow.com\/a\/4651049\n\t\t\/\/ in case another handler displays a confirmation dialog (ex: navigating away\n\t\t\/\/ during an upload), there are two possible outcomes: user clicked \"ok\" or\n\t\t\/\/ \"cancel\"\n\n\t\t\/\/ first timeout handler is called after unload dialog is closed\n\t\tsetTimeout(function() {\n\t\t\tOC._userIsNavigatingAway = true;\n\n\t\t\t\/\/ second timeout event is only called if user cancelled (Chrome),\n\t\t\t\/\/ but in other browsers it might still be triggered, so need to\n\t\t\t\/\/ set a higher delay...\n\t\t\tsetTimeout(function() {\n\t\t\t\tif (!OC._unloadCalled) {\n\t\t\t\t\tOC._userIsNavigatingAway = false;\n\t\t\t\t}\n\t\t\t}, 10000);\n\t\t},1);\n\t});\n\t$(document).on('ajaxError.main', function( event, request, settings ) {\n\t\tif (settings && settings.allowAuthErrors) {\n\t\t\treturn;\n\t\t}\n\t\tOC._processAjaxError(request);\n\t});\n\n\t\/**\n\t * Calls the server periodically to ensure that session and CSRF\n\t * token doesn't expire\n\t *\/\n\tfunction initSessionHeartBeat() {\n\t\t\/\/ interval in seconds\n\t\tvar interval = NaN;\n\t\tif (oc_config.session_lifetime) {\n\t\t\tinterval = Math.floor(oc_config.session_lifetime \/ 2);\n\t\t}\n\t\tinterval = isNaN(interval)? 900: interval;\n\n\t\t\/\/ minimum one minute\n\t\tinterval = Math.max(60, interval);\n\t\t\/\/ max interval in seconds set to 24 hours\n\t\tinterval = Math.min(24 * 3600, interval);\n\n\t\tvar url = OC.generateUrl('\/csrftoken');\n\t\tsetInterval(function() {\n\t\t\t$.ajax(url).then(function(resp) {\n\t\t\t\toc_requesttoken = resp.token;\n\t\t\t\tOC.requestToken = resp.token;\n\t\t\t}).fail(function(e) {\n\t\t\t\tconsole.error('session heartbeat failed', e);\n\t\t\t});\n\t\t}, interval * 1000);\n\t}\n\n\t\/\/ session heartbeat (defaults to enabled)\n\tif (typeof(oc_config.session_keepalive) === 'undefined' ||\n\t\t!!oc_config.session_keepalive) {\n\n\t\tinitSessionHeartBeat();\n\t}\n\n\tOC.registerMenu($('#expand'), $('#expanddiv'), false, true);\n\n\t\/\/ toggle for menus\n\t\/\/$(document).on('mouseup.closemenus keyup', function(event) {\n\t$(document).on('mouseup.closemenus', function(event) {\n\n\t\t\/\/ allow enter as a trigger\n\t\t\/\/ if (event.key && event.key !== \"Enter\") {\n\t\t\/\/ \treturn;\n\t\t\/\/ }\n\n\t\tvar $el = $(event.target);\n\t\tif ($el.closest('.menu').length || $el.closest('.menutoggle').length) {\n\t\t\t\/\/ don't close when clicking on the menu directly or a menu toggle\n\t\t\treturn false;\n\t\t}\n\n\t\tOC.hideMenus();\n\t});\n\n\t\/**\n\t * Set up the main menu toggle to react to media query changes.\n\t * If the screen is small enough, the main menu becomes a toggle.\n\t * If the screen is bigger, the main menu is not a toggle any more.\n\t *\/\n\tfunction setupMainMenu() {\n\n\t\t\/\/ init the more-apps menu\n\t\tOC.registerMenu($('#more-apps > a'), $('#navigation'));\n\n\t\t\/\/ toggle the navigation\n\t\tvar $toggle = $('#header .header-appname-container');\n\t\tvar $navigation = $('#navigation');\n\t\tvar $appmenu = $('#appmenu');\n\n\t\t\/\/ init the menu\n\t\tOC.registerMenu($toggle, $navigation);\n\t\t$toggle.data('oldhref', $toggle.attr('href'));\n\t\t$toggle.attr('href', '#');\n\t\t$navigation.hide();\n\n\t\t\/\/ show loading feedback\n\t\t$navigation.delegate('a', 'click', function(event) {\n\t\t\tvar $app = $(event.target);\n\t\t\tif(!$app.is('a')) {\n\t\t\t\t$app = $app.closest('a');\n\t\t\t}\n\t\t\tif(event.which === 1 && !event.ctrlKey && !event.metaKey) {\n\t\t\t\t$app.addClass('app-loading');\n\t\t\t} else {\n\t\t\t\t\/\/ Close navigation when opening app in\n\t\t\t\t\/\/ a new tab\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\n\t\t$navigation.delegate('a', 'mouseup', function(event) {\n\t\t\tif(event.which === 2) {\n\t\t\t\t\/\/ Close navigation when opening app in\n\t\t\t\t\/\/ a new tab via middle click\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\n\t\t$appmenu.delegate('a', 'click', function(event) {\n\t\t\tvar $app = $(event.target);\n\t\t\tif(!$app.is('a')) {\n\t\t\t\t$app = $app.closest('a');\n\t\t\t}\n\t\t\tif(event.which === 1 && !event.ctrlKey && !event.metaKey) {\n\t\t\t\t$app.addClass('app-loading');\n\t\t\t} else {\n\t\t\t\t\/\/ Close navigation when opening app in\n\t\t\t\t\/\/ a new tab\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction setupUserMenu() {\n\t\tvar $menu = $('#header #settings');\n\n\t\t\/\/ show loading feedback\n\t\t$menu.delegate('a', 'click', function(event) {\n\t\t\tvar $page = $(event.target);\n\t\t\tif (!$page.is('a')) {\n\t\t\t\t$page = $page.closest('a');\n\t\t\t}\n\t\t\tif(event.which === 1 && !event.ctrlKey && !event.metaKey) {\n\t\t\t\t$page.find('img').remove();\n\t\t\t\t$page.find('div').remove(); \/\/ prevent odd double-clicks\n\t\t\t\t$page.prepend($('<div\/>').addClass('icon-loading-small'));\n\t\t\t} else {\n\t\t\t\t\/\/ Close navigation when opening menu entry in\n\t\t\t\t\/\/ a new tab\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\n\t\t$menu.delegate('a', 'mouseup', function(event) {\n\t\t\tif(event.which === 2) {\n\t\t\t\t\/\/ Close navigation when opening app in\n\t\t\t\t\/\/ a new tab via middle click\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction setupContactsMenu() {\n\t\tnew OC.ContactsMenu({\n\t\t\tel: $('#contactsmenu .menu'),\n\t\t\ttrigger: $('#contactsmenu .menutoggle')\n\t\t});\n\t}\n\n\tsetupMainMenu();\n\tsetupUserMenu();\n\tsetupContactsMenu();\n\n\t\/\/ move triangle of apps dropdown to align with app name triangle\n\t\/\/ 2 is the additional offset between the triangles\n\tif($('#navigation').length) {\n\t\t$('#header #nextcloud + .menutoggle').on('click', function(){\n\t\t\t$('#menu-css-helper').remove();\n\t\t\tvar caretPosition = $('.header-appname + .icon-caret').offset().left - 2;\n\t\t\tif(caretPosition > 255) {\n\t\t\t\t\/\/ if the app name is longer than the menu, just put the triangle in the middle\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\t$('head').append('<style id=\"menu-css-helper\">#navigation:after { left: '+ caretPosition +'px; }<\/style>');\n\t\t\t}\n\t\t});\n\t\t$('#header #appmenu .menutoggle').on('click', function() {\n\t\t\t$('#appmenu').toggleClass('menu-open');\n\t\t\tif($('#appmenu').is(':visible')) {\n\t\t\t\t$('#menu-css-helper').remove();\n\t\t\t}\n\t\t});\n\t}\n\n\tvar resizeMenu = function() {\n\t\tvar appList = $('#appmenu li');\n\t\tvar rightHeaderWidth = $('.header-right').outerWidth();\n\t\tvar headerWidth = $('header').outerWidth();\n\t\tvar usePercentualAppMenuLimit = 0.33;\n\t\tvar minAppsDesktop = 8;\n\t\tvar availableWidth =  headerWidth - $('#nextcloud').outerWidth() - (rightHeaderWidth > 210 ? rightHeaderWidth : 210)\n\t\tvar isMobile = $(window).width() < 768;\n\t\tif (!isMobile) {\n\t\t\tavailableWidth = availableWidth * usePercentualAppMenuLimit;\n\t\t}\n\t\tvar appCount = Math.floor((availableWidth \/ $(appList).width()));\n\t\tif (isMobile && appCount > minAppsDesktop) {\n\t\t\tappCount = minAppsDesktop;\n\t\t}\n\t\tif (!isMobile && appCount < minAppsDesktop) {\n\t\t\tappCount = minAppsDesktop;\n\t\t}\n\n\t\t\/\/ show at least 2 apps in the popover\n\t\tif(appList.length-1-appCount >= 1) {\n\t\t\tappCount--;\n\t\t}\n\n\t\t$('#more-apps a').removeClass('active');\n\t\tvar lastShownApp;\n\t\tfor (var k = 0; k < appList.length-1; k++) {\n\t\t\tvar name = $(appList[k]).data('id');\n\t\t\tif(k < appCount) {\n\t\t\t\t$(appList[k]).removeClass('hidden');\n\t\t\t\t$('#apps li[data-id=' + name + ']').addClass('in-header');\n\t\t\t\tlastShownApp = appList[k];\n\t\t\t} else {\n\t\t\t\t$(appList[k]).addClass('hidden');\n\t\t\t\t$('#apps li[data-id=' + name + ']').removeClass('in-header');\n\t\t\t\t\/\/ move active app to last position if it is active\n\t\t\t\tif(appCount > 0 && $(appList[k]).children('a').hasClass('active')) {\n\t\t\t\t\t$(lastShownApp).addClass('hidden');\n\t\t\t\t\t$('#apps li[data-id=' + $(lastShownApp).data('id') + ']').removeClass('in-header');\n\t\t\t\t\t$(appList[k]).removeClass('hidden');\n\t\t\t\t\t$('#apps li[data-id=' + name + ']').addClass('in-header');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t\/\/ show\/hide more apps icon\n\t\tif($('#apps li:not(.in-header)').length === 0) {\n\t\t\t$('#more-apps').hide();\n\t\t\t$('#navigation').hide();\n\t\t} else {\n\t\t\t$('#more-apps').show();\n\t\t}\n\t};\n\t$(window).resize(resizeMenu);\n\tsetTimeout(resizeMenu, 0);\n\n\t\/\/ just add snapper for logged in users\n\tif($('#app-navigation').length && !$('html').hasClass('lte9')) {\n\n\t\t\/\/ App sidebar on mobile\n\t\tvar snapper = new Snap({\n\t\t\telement: document.getElementById('app-content'),\n\t\t\tdisable: 'right',\n\t\t\tmaxPosition: 300, \/\/ $navigation-width\n\t\t\tminDragDistance: 100\n\t\t});\n\n\t\t$('#app-content').prepend('<div id=\"app-navigation-toggle\" class=\"icon-menu\" style=\"display:none;\" tabindex=\"0\"><\/div>');\n\n\t\tvar toggleSnapperOnButton = function(){\n\t\t\tif(snapper.state().state == 'left'){\n\t\t\t\tsnapper.close();\n\t\t\t} else {\n\t\t\t\tsnapper.open('left');\n\t\t\t}\n\t\t};\n\n\t\t$('#app-navigation-toggle').click(function(){\n\t\t\ttoggleSnapperOnButton();\n\t\t});\n\n\t\t$('#app-navigation-toggle').keypress(function(e) {\n\t\t\tif(e.which == 13) {\n\t\t\t\ttoggleSnapperOnButton();\n\t\t\t}\n\t\t});\n\n\t\t\/\/ close sidebar when switching navigation entry\n\t\tvar $appNavigation = $('#app-navigation');\n\t\t$appNavigation.delegate('a, :button', 'click', function(event) {\n\t\t\tvar $target = $(event.target);\n\t\t\t\/\/ don't hide navigation when changing settings or adding things\n\t\t\tif($target.is('.app-navigation-noclose') ||\n\t\t\t\t$target.closest('.app-navigation-noclose').length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif($target.is('.app-navigation-entry-utils-menu-button') ||\n\t\t\t\t$target.closest('.app-navigation-entry-utils-menu-button').length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif($target.is('.add-new') ||\n\t\t\t\t$target.closest('.add-new').length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif($target.is('#app-settings') ||\n\t\t\t\t$target.closest('#app-settings').length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsnapper.close();\n\t\t});\n\n\t\tvar navigationBarSlideGestureEnabled = false;\n\t\tvar navigationBarSlideGestureAllowed = true;\n\t\tvar navigationBarSlideGestureEnablePending = false;\n\n\t\tOC.allowNavigationBarSlideGesture = function() {\n\t\t\tnavigationBarSlideGestureAllowed = true;\n\n\t\t\tif (navigationBarSlideGestureEnablePending) {\n\t\t\t\tsnapper.enable();\n\n\t\t\t\tnavigationBarSlideGestureEnabled = true;\n\t\t\t\tnavigationBarSlideGestureEnablePending = false;\n\t\t\t}\n\t\t};\n\n\t\tOC.disallowNavigationBarSlideGesture = function() {\n\t\t\tnavigationBarSlideGestureAllowed = false;\n\n\t\t\tif (navigationBarSlideGestureEnabled) {\n\t\t\t\tvar endCurrentDrag = true;\n\t\t\t\tsnapper.disable(endCurrentDrag);\n\n\t\t\t\tnavigationBarSlideGestureEnabled = false;\n\t\t\t\tnavigationBarSlideGestureEnablePending = true;\n\t\t\t}\n\t\t};\n\n\t\tvar toggleSnapperOnSize = function() {\n\t\t\tif($(window).width() > 768) {\n\t\t\t\tsnapper.close();\n\t\t\t\tsnapper.disable();\n\n\t\t\t\tnavigationBarSlideGestureEnabled = false;\n\t\t\t\tnavigationBarSlideGestureEnablePending = false;\n\t\t\t} else if (navigationBarSlideGestureAllowed) {\n\t\t\t\tsnapper.enable();\n\n\t\t\t\tnavigationBarSlideGestureEnabled = true;\n\t\t\t\tnavigationBarSlideGestureEnablePending = false;\n\t\t\t} else {\n\t\t\t\tnavigationBarSlideGestureEnablePending = true;\n\t\t\t}\n\t\t};\n\n\t\t$(window).resize(_.debounce(toggleSnapperOnSize, 250));\n\n\t\t\/\/ initial call\n\t\ttoggleSnapperOnSize();\n\n\t}\n\n\t\/\/ Update live timestamps every 30 seconds\n\tsetInterval(function() {\n\t\t$('.live-relative-timestamp').each(function() {\n\t\t\t$(this).text(OC.Util.relativeModifiedDate(parseInt($(this).attr('data-timestamp'), 10)));\n\t\t});\n\t}, 30 * 1000);\n\n\tOC.PasswordConfirmation.init();\n}\n\nOC.PasswordConfirmation = {\n\tcallback: null,\n\tpageLoadTime: null,\n\tinit: function() {\n\t\t$('.password-confirm-required').on('click', _.bind(this.requirePasswordConfirmation, this));\n\t\tthis.pageLoadTime = moment.now();\n\t},\n\n\trequiresPasswordConfirmation: function() {\n\t\tvar serverTimeDiff = this.pageLoadTime - (nc_pageLoad
  13. .
  14. .
  15. .
  16. lot of code.....
  17. .
  18. .
  19. .
  20. {\n\t\t\t\tthis.$filelist.find('.filepicker_element_selected').removeClass('filepicker_element_selected');\n\t\t\t}\n\t\t\t$element.toggleClass('filepicker_element_selected');\n\t\t\tbuttonEnableDisable.prop(\"disabled\", false);\n\t\t} else if ( $element.data('type') === 'dir' ) {\n\t\t\tthis._fillFilePicker(this.$filePicker.data('path') + '\/' + $element.data('entryname'));\n\t\t\tthis._changeButtonsText(type, $element.data('entryname'));\n\t\t\tif (this.$filePicker.data('mimetype').indexOf(\"httpd\/unix-directory\") !== -1) {\n\t\t\t\tbuttonEnableDisable.prop(\"disabled\", false);\n\t\t\t} else {\n\t\t\t\tbuttonEnableDisable.prop(\"disabled\", true);\n\t\t\t}\n\t\t}\n\t},\n\n\t\/**\n\t * Handle\n\t * @param type of action\n\t * @param dir on which to change buttons text\n\t * @private\n\t *\/\n\t_changeButtonsText: function(type, dir) {\n\t\tvar copyText = dir === '' ? t('core', 'Copy') : t('core', 'Copy to {folder}', {folder: dir});\n\t\tvar moveText = dir === '' ? t('core', 'Move') : t('core', 'Move to {folder}', {folder: dir});\n\t\tvar buttons = $('.oc-dialog-buttonrow button');\n\t\tswitch (type) {\n\t\t\tcase this.FILEPICKER_TYPE_CHOOSE:\n\t\t\t\tbreak;\n\t\t\tcase this.FILEPICKER_TYPE_COPY:\n\t\t\t\tbuttons.text(copyText);\n\t\t\t\tbreak;\n\t\t\tcase this.FILEPICKER_TYPE_MOVE:\n\t\t\t\tbuttons.text(moveText);\n\t\t\t\tbreak;\n\t\t\tcase this.FILEPICKER_TYPE_COPY_MOVE:\n\t\t\t\tbuttons.eq(0).text(copyText);\n\t\t\t\tbuttons.eq(1).text(moveText);\n\t\t\t\tbreak;\n\t\t}\n\t}\n};\n\n\n\/* global oc_isadmin *\/\n\nvar oc_debug;\nvar oc_webroot;\n\nvar oc_current_user = document.getElementsByTagName('head')[0].getAttribute('data-user');\nvar oc_requesttoken = document.getElementsByTagName('head')[0].getAttribute('data-requesttoken');\n\nwindow.oc_config = window.oc_config || {};\n\nif (typeof oc_webroot === \"undefined\") {\n\toc_webroot = location.pathname;\n\tvar pos = oc_webroot.indexOf('\/index.php\/');\n\tif (pos !== -1) {\n\t\toc_webroot = oc_webroot.substr(0, pos);\n\t}\n\telse {\n\t\toc_webroot = oc_webroot.substr(0, oc_webroot.lastIndexOf('\/'));\n\t}\n}\nif (typeof console === \"undefined\" || typeof console.log === \"undefined\") {\n\tif (!window.console) {\n\t\twindow.console = {};\n\t}\n\tvar noOp = function() { };\n\tvar methods = ['log', 'debug', 'warn', 'info', 'error', 'assert', 'time', 'timeEnd'];\n\tfor (var i = 0; i < methods.length; i++) {\n\t\tconsole[methods[i]] = noOp;\n\t}\n}\n\n\/**\n* Sanitizes a HTML string by replacing all potential dangerous characters with HTML entities\n* @param {string} s String to sanitize\n* @return {string} Sanitized string\n*\/\nfunction escapeHTML(s) {\n\treturn s.toString().split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;').split('\"').join('&quot;').split('\\'').join('&#039;');\n}\n\n\/** @namespace OCP *\/\nvar OCP = {},\n\t\/**\n\t * @namespace OC\n\t *\/\n\tOC = {\n\tPERMISSION_NONE:0,\n\tPERMISSION_CREATE:4,\n\tPERMISSION_READ:1,\n\tPERMISSION_UPDATE:2,\n\tPERMISSION_DELETE:8,\n\tPERMISSION_SHARE:16,\n\tPERMISSION_ALL:31,\n\tTAG_FAVORITE: '_$!<Favorite>!$_',\n\t\/* jshint camelcase: false *\/\n\t\/**\n\t * Relative path to Nextcloud root.\n\t * For example: \"\/nextcloud\"\n\t *\n\t * @type string\n\t *\n\t * @deprecated since 8.2, use OC.getRootPath() instead\n\t * @see OC#getRootPath\n\t *\/\n\twebroot:oc_webroot,\n\n\t\/**\n\t * Capabilities\n\t *\n\t * @type array\n\t *\/\n\t_capabilities: window.oc_capabilities || null,\n\n\tappswebroots:(typeof oc_appswebroots !== 'undefined') ? oc_appswebroots:false,\n\t\/**\n\t * Currently logged in user or null if none\n\t *\n\t * @type String\n\t * @deprecated use {@link OC.getCurrentUser} instead\n\t *\/\n\tcurrentUser:(typeof oc_current_user!=='undefined')?oc_current_user:false,\n\tconfig: window.oc_config,\n\tappConfig: window.oc_appconfig || {},\n\ttheme: window.oc_defaults || {},\n\tcoreApps:['', 'admin','log','core\/search','settings','core','3rdparty'],\n\trequestToken: oc_requesttoken,\n\tmenuSpeed: 50,\n\n\t\/**\n\t * Get an absolute url to a file in an app\n\t * @param {string} app the id of the app the file belongs to\n\t * @param {string} file the file path relative to the app folder\n\t * @return {string} Absolute URL to a file\n\t *\/\n\tlinkTo:function(app,file){\n\t\treturn OC.filePath(app,'',file);\n\t},\n\n\t\/**\n\t * Creates a relative url for remote use\n\t * @param {string} service id\n\t * @return {string} the url\n\t *\/\n\tlinkToRemoteBase:function(service) {\n\t\treturn OC.getRootPath() + '\/remote.php\/' + service;\n\t},\n\n\t\/**\n\t * @brief Creates an absolute url for remote use\n\t * @param {string} service id\n\t * @return {string} the url\n\t *\/\n\tlinkToRemote:function(service) {\n\t\treturn window.location.protocol + '\/\/' + window.location.host + OC.linkToRemoteBase(service);\n\t},\n\n\t\/**\n\t * Gets the base path for the given OCS API service.\n\t * @param {string} service name\n\t * @param {int} version OCS API version\n\t * @return {string} OCS API base path\n\t *\/\n\tlinkToOCS: function(service, version) {\n\t\tversion = (version !== 2) ? 1 : 2;\n\t\treturn window.location.protocol + '\/\/' + window.location.host + OC.getRootPath() + '\/ocs\/v' + version + '.php\/' + service + '\/';\n\t},\n\n\t\/**\n\t * Generates the absolute url for the given relative url, which can contain parameters.\n\t * Parameters will be URL encoded automatically.\n\t * @param {string} url\n\t * @param [params] params\n\t * @param [options] options\n\t * @param {bool} [options.escape=true] enable\/disable auto escape of placeholders (by default enabled)\n\t * @return {string} Absolute URL for the given relative URL\n\t *\/\n\tgenerateUrl: function(url, params, options) {\n\t\tvar defaultOptions = {\n\t\t\t\tescape: true\n\t\t\t},\n\t\t\tallOptions = options || {};\n\t\t_.defaults(allOptions, defaultOptions);\n\n\t\tvar _build = function (text, vars) {\n\t\t\tvars = vars || [];\n\t\t\treturn text.replace(\/{([^{}]*)}\/g,\n\t\t\t\tfunction (a, b) {\n\t\t\t\t\tvar r = (vars[b]);\n\t\t\t\t\tif(allOptions.escape) {\n\t\t\t\t\t\treturn (typeof r === 'string' || typeof r === 'number') ? encodeURIComponent(r) : encodeURIComponent(a);\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn (typeof r === 'string' || typeof r === 'number') ? r : a;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\t\t};\n\t\tif (url.charAt(0) !== '\/') {\n\t\t\turl = '\/' + url;\n\n\t\t}\n\n\t\tif(oc_config.modRewriteWorking == true) {\n\t\t\treturn OC.getRootPath() + _build(url, params);\n\t\t}\n\n\t\treturn OC.getRootPath() + '\/index.php' + _build(url, params);\n\t},\n\n\t\/**\n\t * Get the absolute url for a file in an app\n\t * @param {string} app the id of the app\n\t * @param {string} type the type of the file to link to (e.g. css,img,ajax.template)\n\t * @param {string} file the filename\n\t * @return {string} Absolute URL for a file in an app\n\t *\/\n\tfilePath:function(app,type,file){\n\t\tvar isCore=OC.coreApps.indexOf(app)!==-1,\n\t\t\tlink=OC.getRootPath();\n\t\tif(file.substring(file.length-3) === 'php' && !isCore){\n\t\t\tlink+='\/index.php\/apps\/' + app;\n\t\t\tif (file != 'index.php') {\n\t\t\t\tlink+='\/';\n\t\t\t\tif(type){\n\t\t\t\t\tlink+=encodeURI(type + '\/');\n\t\t\t\t}\n\t\t\t\tlink+= file;\n\t\t\t}\n\t\t}else if(file.substring(file.length-3) !== 'php' && !isCore){\n\t\t\tlink=OC.appswebroots[app];\n\t\t\tif(type){\n\t\t\t\tlink+= '\/'+type+'\/';\n\t\t\t}\n\t\t\tif(link.substring(link.length-1) !== '\/'){\n\t\t\t\tlink+='\/';\n\t\t\t}\n\t\t\tlink+=file;\n\t\t}else{\n\t\t\tif ((app == 'settings' || app == 'core' || app == 'search') && type == 'ajax') {\n\t\t\t\tlink+='\/index.php\/';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlink+='\/';\n\t\t\t}\n\t\t\tif(!isCore){\n\t\t\t\tlink+='apps\/';\n\t\t\t}\n\t\t\tif (app !== '') {\n\t\t\t\tapp+='\/';\n\t\t\t\tlink+=app;\n\t\t\t}\n\t\t\tif(type){\n\t\t\t\tlink+=type+'\/';\n\t\t\t}\n\t\t\tlink+=file;\n\t\t}\n\t\treturn link;\n\t},\n\n\t\/**\n\t * Check if a user file is allowed to be handled.\n\t * @param {string} file to check\n\t *\/\n\tfileIsBlacklisted: function(file) {\n\t\treturn !!(file.match(oc_config.blacklist_files_regex));\n\t},\n\n\t\/**\n\t * Redirect to the target URL, can also be used for downloads.\n\t * @param {string} targetURL URL to redirect to\n\t *\/\n\tredirect: function(targetURL) {\n\t\twindow.location = targetURL;\n\t},\n\n\t\/**\n\t * Reloads the current page\n\t *\/\n\treload: function() {\n\t\twindow.location.reload();\n\t},\n\n\t\/**\n\t * Protocol that is used to access this Nextcloud instance\n\t * @return {string} Used protocol\n\t *\/\n\tgetProtocol: function() {\n\t\treturn window.location.protocol.split(':')[0];\n\t},\n\n\t\/**\n\t * Returns the host used to access this Nextcloud instance\n\t * Host is sometimes the same as the hostname but now always.\n\t *\n\t * Examples:\n\t * http:\/\/example.com => example.com\n\t * https:\/\/example.com => example.com\n\t * http:\/\/example.com:8080 => example.com:8080\n\t *\n\t * @return {string} host\n\t *\n\t * @since 8.2\n\t *\/\n\tgetHost: function() {\n\t\treturn window.location.host;\n\t},\n\n\t\/**\n\t * Returns the hostname used to access this Nextcloud instance\n\t * The hostname is always stripped of the port\n\t *\n\t * @return {string} hostname\n\t * @since 9.0\n\t *\/\n\tgetHostName: function() {\n\t\treturn window.location.hostname;\n\t},\n\n\t\/**\n\t * Returns the port number used to access this Nextcloud instance\n\t *\n\t * @return {int} port number\n\t *\n\t * @since 8.2\n\t *\/\n\tgetPort: function() {\n\t\treturn window.location.port;\n\t},\n\n\t\/**\n\t * Returns the web root path where this Nextcloud instance\n\t * is accessible, with a leading slash.\n\t * For example \"\/nextcloud\".\n\t *\n\t * @return {string} web root path\n\t *\n\t * @since 8.2\n\t *\/\n\tgetRootPath: function() {\n\t\treturn OC.webroot;\n\t},\n\n\n\t\/**\n\t * Returns the capabilities\n\t *\n\t * @return {array} capabilities\n\t *\n\t * @since 14.0\n\t *\/\n\tgetCapabilities: function() {\n\t\treturn OC._capabilities;\n\t},\n\n\t\/**\n\t * Returns the currently logged in user or null if there is no logged in\n\t * user (public page mode)\n\t *\n\t * @return {OC.CurrentUser} user spec\n\t * @since 9.0.0\n\t *\/\n\tgetCurrentUser: function() {\n\t\tif (_.isUndefined(this._currentUserDisplayName)) {\n\t\t\tthis._currentUserDisplayName = document.getElementsByTagName('head')[0].getAttribute('data-user-displayname');\n\t\t}\n\t\treturn {\n\t\t\tuid: this.currentUser,\n\t\t\tdisplayName: this._currentUserDisplayName\n\t\t};\n\t},\n\n\t\/**\n\t * get the absolute path to an image file\n\t * if no extension is given for the image, it will automatically decide\n\t * between .png and .svg based on what the browser supports\n\t * @param {string} app the app id to which the image belongs\n\t * @param {string} file the name of the image file\n\t * @return {string}\n\t *\/\n\timagePath:function(app,file){\n\t\tif(file.indexOf('.')==-1){\/\/if no extension is given, use svg\n\t\t\tfile+='.svg';\n\t\t}\n\t\treturn OC.filePath(app,'img',file);\n\t},\n\n\t\/**\n\t * URI-Encodes a file path but keep the path slashes.\n\t *\n\t * @param path path\n\t * @return encoded path\n\t *\/\n\tencodePath: function(path) {\n\t\tif (!path) {\n\t\t\treturn path;\n\t\t}\n\t\tvar parts = path.split('\/');\n\t\tvar result = [];\n\t\tfor (var i = 0; i < parts.length; i++) {\n\t\t\tresult.push(encodeURIComponent(parts[i]));\n\t\t}\n\t\treturn result.join('\/');\n\t},\n\n\t\/**\n\t * Load a script for the server and load it. If the script is already loaded,\n\t * the event handler will be called directly\n\t * @param {string} app the app id to which the script belongs\n\t * @param {string} script the filename of the script\n\t * @param ready event handler to be called when the script is loaded\n\t *\/\n\taddScript:function(app,script,ready){\n\t\tvar deferred, path=OC.filePath(app,'js',script+'.js');\n\t\tif(!OC.addScript.loaded[path]) {\n\t\t\tdeferred = $.Deferred();\n\t\t\t$.getScript(path, function() {\n\t\t\t\tdeferred.resolve();\n\t\t\t});\n\t\t\tOC.addScript.loaded[path] = deferred;\n\t\t} else {\n\t\t\tif (ready) {\n\t\t\t\tready();\n\t\t\t}\n\t\t}\n\t\treturn OC.addScript.loaded[path];\n\t},\n\t\/**\n\t * Loads a CSS file\n\t * @param {string} app the app id to which the css style belongs\n\t * @param {string} style the filename of the css file\n\t *\/\n\taddStyle:function(app,style){\n\t\tvar path=OC.filePath(app,'css',style+'.css');\n\t\tif(OC.addStyle.loaded.indexOf(path)===-1){\n\t\t\tOC.addStyle.loaded.push(path);\n\t\t\tif (document.createStyleSheet) {\n\t\t\t\tdocument.createStyleSheet(path);\n\t\t\t} else {\n\t\t\t\tstyle=$('<link rel=\"stylesheet\" type=\"text\/css\" href=\"'+path+'\"\/>');\n\t\t\t\t$('head').append(style);\n\t\t\t}\n\t\t}\n\t},\n\n\t\/**\n\t * Loads translations for the given app asynchronously.\n\t *\n\t * @param {String} app app name\n\t * @param {Function} callback callback to call after loading\n\t * @return {Promise}\n\t *\/\n\taddTranslations: function(app, callback) {\n\t\treturn OC.L10N.load(app, callback);\n\t},\n\n\t\/**\n\t * Returns the base name of the given path.\n\t * For example for \"\/abc\/somefile.txt\" it will return \"somefile.txt\"\n\t *\n\t * @param {String} path\n\t * @return {String} base name\n\t *\/\n\tbasename: function(path) {\n\t\treturn path.replace(\/\\\\\/g,'\/').replace( \/.*\\\/\/, '' );\n\t},\n\n\t\/**\n\t * Returns the dir name of the given path.\n\t * For example for \"\/abc\/somefile.txt\" it will return \"\/abc\"\n\t *\n\t * @param {String} path\n\t * @return {String} dir name\n\t *\/\n\tdirname: function(path) {\n\t\treturn path.replace(\/\\\\\/g,'\/').replace(\/\\\/[^\\\/]*$\/, '');\n\t},\n\n\t\/**\n\t * Returns whether the given paths are the same, without\n\t * leading, trailing or doubled slashes and also removing\n\t * the dot sections.\n\t *\n\t * @param {String} path1 first path\n\t * @param {String} path2 second path\n\t * @return {bool} true if the paths are the same\n\t *\n\t * @since 9.0\n\t *\/\n\tisSamePath: function(path1, path2) {\n\t\tvar filterDot = function(p) {\n\t\t\treturn p !== '.';\n\t\t};\n\t\tvar pathSections1 = _.filter((path1 || '').split('\/'), filterDot);\n\t\tvar pathSections2 = _.filter((path2 || '').split('\/'), filterDot);\n\t\tpath1 = OC.joinPaths.apply(OC, pathSections1);\n\t\tpath2 = OC.joinPaths.apply(OC, pathSections2);\n\t\treturn path1 === path2;\n\t},\n\n\t\/**\n\t * Join path sections\n\t *\n\t * @param {...String} path sections\n\t *\n\t * @return {String} joined path, any leading or trailing slash\n\t * will be kept\n\t *\n\t * @since 8.2\n\t *\/\n\tjoinPaths: function() {\n\t\tif (arguments.length < 1) {\n\t\t\treturn '';\n\t\t}\n\t\tvar path = '';\n\t\t\/\/ convert to array\n\t\tvar args = Array.prototype.slice.call(arguments);\n\t\t\/\/ discard empty arguments\n\t\targs = _.filter(args, function(arg) {\n\t\t\treturn arg.length > 0;\n\t\t});\n\t\tif (args.length < 1) {\n\t\t\treturn '';\n\t\t}\n\n\t\tvar lastArg = args[args.length - 1];\n\t\tvar leadingSlash = args[0].charAt(0) === '\/';\n\t\tvar trailingSlash = lastArg.charAt(lastArg.length - 1) === '\/';\n\t\tvar sections = [];\n\t\tvar i;\n\t\tfor (i = 0; i < args.length; i++) {\n\t\t\tsections = sections.concat(args[i].split('\/'));\n\t\t}\n\t\tvar first = !leadingSlash;\n\t\tfor (i = 0; i < sections.length; i++) {\n\t\t\tif (sections[i] !== '') {\n\t\t\t\tif (first) {\n\t\t\t\t\tfirst = false;\n\t\t\t\t} else {\n\t\t\t\t\tpath += '\/';\n\t\t\t\t}\n\t\t\t\tpath += sections[i];\n\t\t\t}\n\t\t}\n\n\t\tif (trailingSlash) {\n\t\t\t\/\/ add it back\n\t\t\tpath += '\/';\n\t\t}\n\t\treturn path;\n\t},\n\n\t\/**\n\t * Do a search query and display the results\n\t * @param {string} query the search query\n\t *\/\n\tsearch: function (query) {\n\t\tOC.Search.search(query, null, 0, 30);\n\t},\n\t\/**\n\t * Dialog helper for jquery dialogs.\n\t *\n\t * @namespace OC.dialogs\n\t *\/\n\tdialogs:OCdialogs,\n\t\/**\n\t * Parses a URL query string into a JS map\n\t * @param {string} queryString query string in the format param1=1234&param2=abcde&param3=xyz\n\t * @return {Object.<string, string>} map containing key\/values matching the URL parameters\n\t *\/\n\tparseQueryString:function(queryString){\n\t\tvar parts,\n\t\t\tpos,\n\t\t\tcomponents,\n\t\t\tresult = {},\n\t\t\tkey,\n\t\t\tvalue;\n\t\tif (!queryString){\n\t\t\treturn null;\n\t\t}\n\t\tpos = queryString.indexOf('?');\n\t\tif (pos >= 0){\n\t\t\tqueryString = queryString.substr(pos + 1);\n\t\t}\n\t\tparts = queryString.replace(\/\\+\/g, '%20').split('&');\n\t\tfor (var i = 0; i < parts.length; i++){\n\t\t\t\/\/ split on first equal sign\n\t\t\tvar part = parts[i];\n\t\t\tpos = part.indexOf('=');\n\t\t\tif (pos >= 0) {\n\t\t\t\tcomponents = [\n\t\t\t\t\tpart.substr(0, pos),\n\t\t\t\t\tpart.substr(pos + 1)\n\t\t\t\t];\n\t\t\t}\n\t\t\telse {\n\t\t\t\t\/\/ key only\n\t\t\t\tcomponents = [part];\n\t\t\t}\n\t\t\tif (!components.length){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tkey = decodeURIComponent(components[0]);\n\t\t\tif (!key){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\/\/ if equal sign was there, return string\n\t\t\tif (components.length > 1) {\n\t\t\t\tresult[key] = decodeURIComponent(components[1]);\n\t\t\t}\n\t\t\t\/\/ no equal sign => null value\n\t\t\telse {\n\t\t\t\tresult[key] = null;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t},\n\n\t\/**\n\t * Builds a URL query from a JS map.\n\t * @param {Object.<string, string>} params map containing key\/values matching the URL parameters\n\t * @return {string} String containing a URL query (without question) mark\n\t *\/\n\tbuildQueryString: function(params) {\n\t\tif (!params) {\n\t\t\treturn '';\n\t\t}\n\t\treturn $.map(params, function(value, key) {\n\t\t\tvar s = encodeURIComponent(key);\n\t\t\tif (value !== null && typeof(value) !== 'undefined') {\n\t\t\t\ts += '=' + encodeURIComponent(value);\n\t\t\t}\n\t\t\treturn s;\n\t\t}).join('&');\n\t},\n\n\t\/**\n\t * Opens a popup with the setting for an app.\n\t * @param {string} appid The ID of the app e.g. 'calendar', 'contacts' or 'files'.\n\t * @param {boolean|string}\u00a0loadJS If true 'js\/settings.js' is loaded. If it's a string\n\t * it will attempt to load a script by that name in the 'js' directory.\n\t * @param {boolean} [cache] If true the javascript file won't be forced refreshed. Defaults to true.\n\t * @param {string} [scriptName] The name of the PHP file to load. Defaults to 'settings.php' in\n\t * the root of the app directory hierarchy.\n\t *\/\n\tappSettings:function(args) {\n\t\tif(typeof args === 'undefined' || typeof args.appid === 'undefined') {\n\t\t\tthrow { name: 'MissingParameter', message: 'The parameter appid is missing' };\n\t\t}\n\t\tvar props = {scriptName:'settings.php', cache:true};\n\t\t$.extend(props, args);\n\t\tvar settings = $('#appsettings');\n\t\tif(settings.length === 0) {\n\t\t\tthrow { name: 'MissingDOMElement', message: 'There has be be an element with id \"appsettings\" for the popup to show.' };\n\t\t}\n\t\tvar popup = $('#appsettings_popup');\n\t\tif(popup.length === 0) {\n\t\t\t$('body').prepend('<div class=\"popup hidden\" id=\"appsettings_popup\"><\/div>');\n\t\t\tpopup = $('#appsettings_popup');\n\t\t\tpopup.addClass(settings.hasClass('topright') ? 'topright' : 'bottomleft');\n\t\t}\n\t\tif(popup.is(':visible')) {\n\t\t\tpopup.hide().remove();\n\t\t} else {\n\t\t\tvar arrowclass = settings.hasClass('topright') ? 'up' : 'left';\n\t\t\tvar jqxhr = $.get(OC.filePath(props.appid, '', props.scriptName), function(data) {\n\t\t\t\tpopup.html(data).ready(function() {\n\t\t\t\t\tpopup.prepend('<span class=\"arrow '+arrowclass+'\"><\/span><h2>'+t('core', 'Settings')+'<\/h2><a class=\"close\"><\/a>').show();\n\t\t\t\t\tpopup.find('.close').bind('click', function() {\n\t\t\t\t\t\tpopup.remove();\n\t\t\t\t\t});\n\t\t\t\t\tif(typeof props.loadJS !== 'undefined') {\n\t\t\t\t\t\tvar scriptname;\n\t\t\t\t\t\tif(props.loadJS === true) {\n\t\t\t\t\t\t\tscriptname = 'settings.js';\n\t\t\t\t\t\t} else if(typeof props.loadJS === 'string') {\n\t\t\t\t\t\t\tscriptname = props.loadJS;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow { name: 'InvalidParameter', message: 'The \"loadJS\" parameter must be either boolean or a string.' };\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(props.cache) {\n\t\t\t\t\t\t\t$.ajaxSetup({cache: true});\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$.getScript(OC.filePath(props.appid, 'js', scriptname))\n\t\t\t\t\t\t.fail(function(jqxhr, settings, e) {\n\t\t\t\t\t\t\tthrow e;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}).show();\n\t\t\t}, 'html');\n\t\t}\n\t},\n\n\t\/**\n\t * For menu toggling\n\t * @todo Write documentation\n\t *\n\t * @param {jQuery} $toggle\n\t * @param {jQuery} $menuEl\n\t * @param {function|undefined} toggle callback invoked everytime the menu is opened\n\t * @param {boolean} headerMenu is this a top right header menu?\n\t * @returns {undefined}\n\t *\/\n\tregisterMenu: function($toggle, $menuEl, toggle, headerMenu) {\n\t\tvar self = this;\n\t\t$menuEl.addClass('menu');\n\n\t\t\/\/ On link, the enter key trigger a click event\n\t\t\/\/ Only use the click to avoid two fired events\n\t\t$toggle.on($toggle.prop('tagName') === 'A'\n\t\t\t? 'click.menu'\n\t\t\t: 'click.menu keyup.menu', function(event) {\n\t\t\t\/\/ prevent the link event (append anchor to URL)\n\t\t\tevent.preventDefault();\n\n\t\t\t\/\/ allow enter key as a trigger\n\t\t\tif (event.key && event.key !== \"Enter\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ($menuEl.is(OC._currentMenu)) {\n\t\t\t\tself.hideMenus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\/\/ another menu was open?\n\t\t\telse if (OC._currentMenu) {\n\t\t\t\t\/\/ close it\n\t\t\t\tself.hideMenus();\n\t\t\t}\n\n\t\t\tif (headerMenu === true) {\n\t\t\t\t$menuEl.parent().addClass('openedMenu');\n\t\t\t}\n\n\t\t\t\/\/ Set menu to expanded\n\t\t\t$toggle.attr('aria-expanded', true);\n\n\t\t\t$menuEl.slideToggle(OC.menuSpeed, toggle);\n\t\t\tOC._currentMenu = $menuEl;\n\t\t\tOC._currentMenuToggle = $toggle;\n\t\t});\n\t},\n\n\t\/**\n\t *  @todo Write documentation\n\t *\/\n\tunregisterMenu: function($toggle, $menuEl) {\n\t\t\/\/ close menu if opened\n\t\tif ($menuEl.is(OC._currentMenu)) {\n\t\t\tthis.hideMenus();\n\t\t}\n\t\t$toggle.off('click.menu').removeClass('menutoggle');\n\t\t$menuEl.removeClass('menu');\n\t},\n\n\t\/**\n\t * Hides any open menus\n\t *\n\t * @param {Function} complete callback when the hiding animation is done\n\t *\/\n\thideMenus: function(complete) {\n\t\tif (OC._currentMenu) {\n\t\t\tvar lastMenu = OC._currentMenu;\n\t\t\tOC._currentMenu.trigger(new $.Event('beforeHide'));\n\t\t\tOC._currentMenu.slideUp(OC.menuSpeed, function() {\n\t\t\t\tlastMenu.trigger(new $.Event('afterHide'));\n\t\t\t\tif (complete) {\n\t\t\t\t\tcomplete.apply(this, arguments);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t\/\/ Set menu to closed\n\t\t$('.menutoggle').attr('aria-expanded', false);\n\n\t\t$('.openedMenu').removeClass('openedMenu');\n\t\tOC._currentMenu = null;\n\t\tOC._currentMenuToggle = null;\n\t},\n\n\t\/**\n\t * Shows a given element as menu\n\t *\n\t * @param {Object} [$toggle=null] menu toggle\n\t * @param {Object} $menuEl menu element\n\t * @param {Function} complete callback when the showing animation is done\n\t *\/\n\tshowMenu: function($toggle, $menuEl, complete) {\n\t\tif ($menuEl.is(OC._currentMenu)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.hideMenus();\n\t\tOC._currentMenu = $menuEl;\n\t\tOC._currentMenuToggle = $toggle;\n\t\t$menuEl.trigger(new $.Event('beforeShow'));\n\t\t$menuEl.show();\n\t\t$menuEl.trigger(new $.Event('afterShow'));\n\t\t\/\/ no animation\n\t\tif (_.isFunction(complete)) {\n\t\t\tcomplete();\n\t\t}\n\t},\n\n\t\/**\n\t * Wrapper for matchMedia\n\t *\n\t * This is makes it possible for unit tests to\n\t * stub matchMedia (which doesn't work in PhantomJS)\n\t * @private\n\t *\/\n\t_matchMedia: function(media) {\n\t\tif (window.matchMedia) {\n\t\t\treturn window.matchMedia(media);\n\t\t}\n\t\treturn false;\n\t},\n\n\t\/**\n\t * Returns the user's locale as a BCP 47 compliant language tag\n\t *\n\t * @return {String} locale string\n\t *\/\n\tgetCanonicalLocale: function() {\n\t\tvar locale = this.getLocale();\n\t\treturn typeof locale === 'string' ? locale.replace(\/_\/g, '-') : locale;\n\t},\n\n\t\/**\n\t * Returns the user's locale\n\t *\n\t * @return {String} locale string\n\t *\/\n\tgetLocale: function() {\n\t\treturn $('html').data('locale');\n\t},\n\n\t\/**\n\t * Returns the user's language\n\t *\n\t * @returns {String} language string\n\t *\/\n\tgetLanguage: function () {\n\t\treturn $('html').prop('lang');\n\t},\n\n\t\/**\n\t * Returns whether the current user is an administrator\n\t *\n\t * @return {bool} true if the user is an admin, false otherwise\n\t * @since 9.0.0\n\t *\/\n\tisUserAdmin: function() {\n\t\treturn oc_isadmin;\n\t},\n\n\t\/**\n\t * Warn users that the connection to the server was lost temporarily\n\t *\n\t * This function is throttled to prevent stacked notfications.\n\t * After 7sec the first notification is gone, then we can show another one\n\t * if necessary.\n\t *\/\n\t_ajaxConnectionLostHandler: _.throttle(function() {\n\t\tOC.Notification.showTemporary(t('core', 'Connection to server lost'));\n\t}, 7 * 1000, {trailing: false}),\n\n\t\/**\n\t * Process ajax error, redirects to main page\n\t * if an error\/auth error status was returned.\n\t *\/\n\t_processAjaxError: function(xhr) {\n\t\tvar self = this;\n\t\t\/\/ purposefully aborted request ?\n\t\t\/\/ this._userIsNavigatingAway needed to distinguish ajax calls cancelled by navigating away\n\t\t\/\/ from calls cancelled by failed cross-domain ajax due to SSO redirect\n\t\tif (xhr.status === 0 && (xhr.statusText === 'abort' || xhr.statusText === 'timeout' || self._reloadCalled)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (_.contains([302, 303, 307, 401], xhr.status) && OC.currentUser) {\n\t\t\t\/\/ sometimes \"beforeunload\" happens later, so need to defer the reload a bit\n\t\t\tsetTimeout(function() {\n\t\t\t\tif (!self._userIsNavigatingAway && !self._reloadCalled) {\n\t\t\t\t\tvar timer = 0;\n\t\t\t\t\tvar seconds = 5;\n\t\t\t\t\tvar interval = setInterval( function() {\n\t\t\t\t\t\tOC.Notification.showUpdate(n('core', 'Problem loading page, reloading in %n second', 'Problem loading page, reloading in %n seconds', seconds - timer));\n\t\t\t\t\t\tif (timer >= seconds) {\n\t\t\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\t\t\tOC.reload();\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttimer++;\n\t\t\t\t\t\t}, 1000 \/\/ 1 second interval\n\t\t\t\t\t);\n\n\t\t\t\t\t\/\/ only call reload once\n\t\t\t\t\tself._reloadCalled = true;\n\t\t\t\t}\n\t\t\t}, 100);\n\t\t} else if(xhr.status === 0) {\n\t\t\t\/\/ Connection lost (e.g. WiFi disconnected or server is down)\n\t\t\tsetTimeout(function() {\n\t\t\t\tif (!self._userIsNavigatingAway && !self._reloadCalled) {\n\t\t\t\t\tself._ajaxConnectionLostHandler();\n\t\t\t\t}\n\t\t\t}, 100);\n\t\t}\n\t},\n\n\t\/**\n\t * Registers XmlHttpRequest object for global error processing.\n\t *\n\t * This means that if this XHR object returns 401 or session timeout errors,\n\t * the current page will automatically be reloaded.\n\t *\n\t * @param {XMLHttpRequest} xhr\n\t *\/\n\tregisterXHRForErrorProcessing: function(xhr) {\n\t\tvar loadCallback = function() {\n\t\t\tif (xhr.readyState !== 4) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t\/\/ fire jquery global ajax error handler\n\t\t\t$(document).trigger(new $.Event('ajaxError'), xhr);\n\t\t};\n\n\t\tvar errorCallback = function() {\n\t\t\t\/\/ fire jquery global ajax error handler\n\t\t\t$(document).trigger(new $.Event('ajaxError'), xhr);\n\t\t};\n\n\t\tif (xhr.addEventListener) {\n\t\t\txhr.addEventListener('load', loadCallback);\n\t\t\txhr.addEventListener('error', errorCallback);\n\t\t}\n\n\t}\n};\n\n\/**\n * Current user attributes\n *\n * @typedef {Object} OC.CurrentUser\n *\n * @property {String} uid user id\n * @property {String} displayName display name\n *\/\n\n\/**\n * @namespace OC.Plugins\n *\/\nOC.Plugins = {\n\t\/**\n\t * @type Array.<OC.Plugin>\n\t *\/\n\t_plugins: {},\n\n\t\/**\n\t * Register plugin\n\t *\n\t * @param {String} targetName app name \/ class name to hook into\n\t * @param {OC.Plugin} plugin\n\t *\/\n\tregister: function(targetName, plugin) {\n\t\tvar plugins = this._plugins[targetName];\n\t\tif (!plugins) {\n\t\t\tplugins = this._plugins[targetName] = [];\n\t\t}\n\t\tplugins.push(plugin);\n\t},\n\n\t\/**\n\t * Returns all plugin registered to the given target\n\t * name \/ app name \/ class name.\n\t *\n\t * @param {String} targetName app name \/ class name to hook into\n\t * @return {Array.<OC.Plugin>} array of plugins\n\t *\/\n\tgetPlugins: function(targetName) {\n\t\treturn this._plugins[targetName] || [];\n\t},\n\n\t\/**\n\t * Call attach() on all plugins registered to the given target name.\n\t *\n\t * @param {String} targetName app name \/ class name\n\t * @param {Object} object to be extended\n\t * @param {Object} [options] options\n\t *\/\n\tattach: function(targetName, targetObject, options) {\n\t\tvar plugins = this.getPlugins(targetName);\n\t\tfor (var i = 0; i < plugins.length; i++) {\n\t\t\tif (plugins[i].attach) {\n\t\t\t\tplugins[i].attach(targetObject, options);\n\t\t\t}\n\t\t}\n\t},\n\n\t\/**\n\t * Call detach() on all plugins registered to the given target name.\n\t *\n\t * @param {String} targetName app name \/ class name\n\t * @param {Object} object to be extended\n\t * @param {Object} [options] options\n\t *\/\n\tdetach: function(targetName, targetObject, options) {\n\t\tvar plugins = this.getPlugins(targetName);\n\t\tfor (var i = 0; i < plugins.length; i++) {\n\t\t\tif (plugins[i].detach) {\n\t\t\t\tplugins[i].detach(targetObject, options);\n\t\t\t}\n\t\t}\n\t},\n\n\t\/**\n\t * Plugin\n\t *\n\t * @todo make this a real class in the future\n\t * @typedef {Object} OC.Plugin\n\t *\n\t * @property {String} name plugin name\n\t * @property {Function} attach function that will be called when the\n\t * plugin is attached\n\t * @property {Function} [detach] function that will be called when the\n\t * plugin is detached\n\t *\/\n\n};\n\n\/**\n * @namespace OC.search\n *\/\nOC.search.customResults = {};\n\/**\n * @deprecated use get\/setFormatter() instead\n *\/\nOC.search.resultTypes = {};\n\nOC.addStyle.loaded=[];\nOC.addScript.loaded=[];\n\n\/**\n * A little class to manage a status field for a \"saving\" process.\n * It can be used to display a starting message (e.g. \"Saving...\") and then\n * replace it with a green success message or a red error message.\n *\n * @namespace OC.msg\n *\/\nOC.msg = {\n\t\/**\n\t * Displayes a \"Saving...\" message in the given message placeholder\n\t *\n\t * @param {Object} selector\tPlaceholder to display the message in\n\t *\/\n\tstartSaving: function(selector) {\n\t\tthis.startAction(selector, t('core', 'Saving...'));\n\t},\n\n\t\/**\n\t * Displayes a custom message in the given message placeholder\n\t *\n\t * @param {Object} selector\tPlaceholder to display the message in\n\t * @param {string} message\tPlain text message to display (no HTML allowed)\n\t *\/\n\tstartAction: function(selector, message) {\n\t\t$(selector).text(message)\n\t\t\t.removeClass('success')\n\t\t\t.removeClass('error')\n\t\t\t.stop(true, true)\n\t\t\t.show();\n\t},\n\n\t\/**\n\t * Displayes an success\/error message in the given selector\n\t *\n\t * @param {Object} selector\tPlaceholder to display the message in\n\t * @param {Object} response\tResponse of the server\n\t * @param {Object} response.data\tData of the servers response\n\t * @param {string} response.data.message\tPlain text message to display (no HTML allowed)\n\t * @param {string} response.status\tis being used to decide whether the message\n\t * is displayed as an error\/success\n\t *\/\n\tfinishedSaving: function(selector, response) {\n\t\tthis.finishedAction(selector, response);\n\t},\n\n\t\/**\n\t * Displayes an success\/error message in the given selector\n\t *\n\t * @param {Object} selector\tPlaceholder to display the message in\n\t * @param {Object} response\tResponse of the server\n\t * @param {Object} response.data Data of the servers response\n\t * @param {string} response.data.message Plain text message to display (no HTML allowed)\n\t * @param {string} response.status is being used to decide whether the message\n\t * is displayed as an error\/success\n\t *\/\n\tfinishedAction: function(selector, response) {\n\t\tif (response.status === \"success\") {\n\t\t\tthis.finishedSuccess(selector, response.data.message);\n\t\t} else {\n\t\t\tthis.finishedError(selector, response.data.message);\n\t\t}\n\t},\n\n\t\/**\n\t * Displayes an success message in the given selector\n\t *\n\t * @param {Object} selector Placeholder to display the message in\n\t * @param {string} message Plain text success message to display (no HTML allowed)\n\t *\/\n\tfinishedSuccess: function(selector, message) {\n\t\t$(selector).text(message)\n\t\t\t.addClass('success')\n\t\t\t.removeClass('error')\n\t\t\t.stop(true, true)\n\t\t\t.delay(3000)\n\t\t\t.fadeOut(900)\n\t\t\t.show();\n\t},\n\n\t\/**\n\t * Displayes an error message in the given selector\n\t *\n\t * @param {Object} selector Placeholder to display the message in\n\t * @param {string} message Plain text error message to display (no HTML allowed)\n\t *\/\n\tfinishedError: function(selector, message) {\n\t\t$(selector).text(message)\n\t\t\t.addClass('error')\n\t\t\t.removeClass('success')\n\t\t\t.show();\n\t}\n};\n\n\/**\n * @todo Write documentation\n * @namespace\n *\/\nOC.Notification={\n\tqueuedNotifications: [],\n\tgetDefaultNotificationFunction: null,\n\n\t\/**\n\t * @type Array<int>\n\t * @description array of notification timers\n\t *\/\n\tnotificationTimers: [],\n\n\t\/**\n\t * @param callback\n\t * @todo Write documentation\n\t *\/\n\tsetDefault: function(callback) {\n\t\tOC.Notification.getDefaultNotificationFunction = callback;\n\t},\n\n\t\/**\n\t * Hides a notification.\n\t *\n\t * If a row is given, only hide that one.\n\t * If no row is given, hide all notifications.\n\t *\n\t * @param {jQuery} [$row] notification row\n\t * @param {Function} [callback] callback\n\t *\/\n\thide: function($row, callback) {\n\t\tvar self = this;\n\t\tvar $notification = $('#notification');\n\n\t\tif (_.isFunction($row)) {\n\t\t\t\/\/ first arg is the callback\n\t\t\tcallback = $row;\n\t\t\t$row = undefined;\n\t\t}\n\n\t\tif (!$row) {\n\t\t\tconsole.warn('Missing argument $row in OC.Notification.hide() call, caller needs to be adjusted to only dismiss its own notification');\n\t\t\t\/\/ assume that the row to be hidden is the first one\n\t\t\t$row = $notification.find('.row:first');\n\t\t}\n\n\t\tif ($row && $notification.find('.row').length > 1) {\n\t\t\t\/\/ remove the row directly\n\t\t\t$row.remove();\n\t\t\tif (callback) {\n\t\t\t\tcallback.call();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t_.defer(function() {\n\t\t\t\/\/ fade out is supposed to only fade when there is a single row\n\t\t\t\/\/ however, some code might call hide() and show() directly after,\n\t\t\t\/\/ which results in more than one element\n\t\t\t\/\/ in this case, simply delete that one element that was supposed to\n\t\t\t\/\/ fade out\n\t\t\t\/\/\n\t\t\t\/\/ FIXME: remove once all callers are adjusted to only hide their own notifications\n\t\t\tif ($notification.find('.row').length > 1) {\n\t\t\t\t$row.remove();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t\/\/ else, fade out whatever was present\n\t\t\t$notification.fadeOut('400', function(){\n\t\t\t\tif (self.isHidden()) {\n\t\t\t\t\tif (self.getDefaultNotificationFunction) {\n\t\t\t\t\t\tself.getDefaultNotificationFunction.call();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (callback) {\n\t\t\t\t\tcallback.call();\n\t\t\t\t}\n\t\t\t\t$notification.empty();\n\t\t\t});\n\t\t});\n\t},\n\n\t\/**\n\t * Shows a notification as HTML without being sanitized before.\n\t * If you pass unsanitized user input this may lead to a XSS vulnerability.\n\t * Consider using show() instead of showHTML()\n\t *\n\t * @param {string} html Message to display\n\t * @param {Object} [options] options\n\t * @param {string} [options.type] notification type\n\t * @param {int} [options.timeout=0] timeout value, defaults to 0 (permanent)\n\t * @return {jQuery} jQuery element for notification row\n\t *\/\n\tshowHtml: function(html, options) {\n\t\toptions = options || {};\n\t\t_.defaults(options, {\n\t\t\ttimeout: 0\n\t\t});\n\n\t\tvar self = this;\n\t\tvar $notification = $('#notification');\n\t\tif (this.isHidden()) {\n\t\t\t$notification.fadeIn().css('display','inline-block');\n\t\t}\n\t\tvar $row = $('<div class=\"row\"><\/div>');\n\t\tif (options.type) {\n\t\t\t$row.addClass('type-' + options.type);\n\t\t}\n\t\tif (options.type === 'error') {\n\t\t\t\/\/ add a close button\n\t\t\tvar $closeButton = $('<a class=\"action close icon-close\" href=\"#\"><\/a>');\n\t\t\t$closeButton.attr('alt', t('core', 'Dismiss'));\n\t\t\t$row.append($closeButton);\n\t\t\t$closeButton.one('click', function() {\n\t\t\t\tself.hide($row);\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\t$row.addClass('closeable');\n\t\t}\n\n\t\t$row.prepend(html);\n\t\t$notification.append($row);\n\n\t\tif(options.timeout > 0) {\n\t\t\t\/\/ register timeout to vanish notification\n\t\t\tthis.notificationTimers.push(setTimeout(function() {\n\t\t\t\tself.hide($row);\n\t\t\t}, (options.timeout * 1000)));\n\t\t}\n\n\t\treturn $row;\n\t},\n\n\t\/**\n\t * Shows a sanitized notification\n\t *\n\t * @param {string} text Message to display\n\t * @param {Object} [options] options\n\t * @param {string} [options.type] notification type\n\t * @param {int} [options.timeout=0] timeout value, defaults to 0 (permanent)\n\t * @return {jQuery} jQuery element for notification row\n\t *\/\n\tshow: function(text, options) {\n\t\treturn this.showHtml($('<div\/>').text(text).html(), options);\n\t},\n\n\t\/**\n\t * Updates (replaces) a sanitized notification.\n\t *\n\t * @param {string} text Message to display\n\t * @return {jQuery} JQuery element for notificaiton row\n\t *\/\n\tshowUpdate: function(text) {\n\t\tvar $notification = $('#notification');\n\t\t\/\/ sanitise\n\t\tvar $html = $('<div\/>').text(text).html();\n\n\t\t\/\/ new notification\n\t\tif (text && $notification.find('.row').length == 0) {\n\t\t\treturn this.showHtml($html);\n\t\t}\n\n\t\tvar $row = $('<div class=\"row\"><\/div>').prepend($html);\n\n\t\t\/\/ just update html in notification\n\t\t$notification.html($row);\n\n\t\treturn $row;\n\t},\n\n\t\/**\n\t * Shows a notification that disappears after x seconds, default is\n\t * 7 seconds\n\t *\n\t * @param {string} text Message to show\n\t * @param {array} [options] options array\n\t * @param {int} [options.timeout=7] timeout in seconds, if this is 0 it will show the message permanently\n\t * @param {boolean} [options.isHTML=false] an indicator for HTML notifications (true) or text (false)\n\t * @param {string} [options.type] notification type\n\t *\/\n\tshowTemporary: function(text, options) {\n\t\tvar defaults = {\n\t\t\tisHTML: false,\n\t\t\ttimeout: 7\n\t\t};\n\t\toptions = options || {};\n\t\t\/\/ merge defaults with passed in options\n\t\t_.defaults(options, defaults);\n\n\t\tvar $row;\n\t\tif(options.isHTML) {\n\t\t\t$row = this.showHtml(text, options);\n\t\t} else {\n\t\t\t$row = this.show(text, options);\n\t\t}\n\t\treturn $row;\n\t},\n\n\t\/**\n\t * Returns whether a notification is hidden.\n\t * @return {boolean}\n\t *\/\n\tisHidden: function() {\n\t\treturn !$(\"#notification\").find('.row').length;\n\t}\n};\n\n\/**\n * Initializes core\n *\/\nfunction initCore() {\n\t\/**\n\t * Disable automatic evaluation of responses for $.ajax() functions (and its\n\t * higher-level alternatives like $.get() and $.post()).\n\t *\n\t * If a response to a $.ajax() request returns a content type of \"application\/javascript\"\n\t * JQuery would previously execute the response body. This is a pretty unexpected\n\t * behaviour and can result in a bypass of our Content-Security-Policy as well as\n\t * multiple unexpected XSS vectors.\n\t *\/\n\t$.ajaxSetup({\n\t\tcontents: {\n\t\t\tscript: false\n\t\t}\n\t});\n\n\t\/**\n\t * Disable execution of eval in jQuery. We do require an allowed eval CSP\n\t * configuration at the moment for handlebars et al. But for jQuery there is\n\t * not much of a reason to execute JavaScript directly via eval.\n\t *\n\t * This thus mitigates some unexpected XSS vectors.\n\t *\/\n\tjQuery.globalEval = function(){};\n\n\t\/**\n\t * Set users locale to moment.js as soon as possible\n\t *\/\n\tmoment.locale(OC.getLocale());\n\n\tvar userAgent = window.navigator.userAgent;\n\tvar msie = userAgent.indexOf('MSIE ');\n\tvar trident = userAgent.indexOf('Trident\/');\n\tvar edge = userAgent.indexOf('Edge\/');\n\n\tif (msie > 0 || trident > 0) {\n\t\t\/\/ (IE 10 or older) || IE 11\n\t\t$('html').addClass('ie');\n\t} else if (edge > 0) {\n\t\t\/\/ for edge\n\t\t$('html').addClass('edge');\n\t}\n\n\t\/\/ css variables fallback for IE\n\tif (msie > 0 || trident > 0) {\n\t\tcssVars();\n\t}\n\n\t$(window).on('unload.main', function() {\n\t\tOC._unloadCalled = true;\n\t});\n\t$(window).on('beforeunload.main', function() {\n\t\t\/\/ super-trick thanks to http:\/\/stackoverflow.com\/a\/4651049\n\t\t\/\/ in case another handler displays a confirmation dialog (ex: navigating away\n\t\t\/\/ during an upload), there are two possible outcomes: user clicked \"ok\" or\n\t\t\/\/ \"cancel\"\n\n\t\t\/\/ first timeout handler is called after unload dialog is closed\n\t\tsetTimeout(function() {\n\t\t\tOC._userIsNavigatingAway = true;\n\n\t\t\t\/\/ second timeout event is only called if user cancelled (Chrome),\n\t\t\t\/\/ but in other browsers it might still be triggered, so need to\n\t\t\t\/\/ set a higher delay...\n\t\t\tsetTimeout(function() {\n\t\t\t\tif (!OC._unloadCalled) {\n\t\t\t\t\tOC._userIsNavigatingAway = false;\n\t\t\t\t}\n\t\t\t}, 10000);\n\t\t},1);\n\t});\n\t$(document).on('ajaxError.main', function( event, request, settings ) {\n\t\tif (settings && settings.allowAuthErrors) {\n\t\t\treturn;\n\t\t}\n\t\tOC._processAjaxError(request);\n\t});\n\n\t\/**\n\t * Calls the server periodically to ensure that session and CSRF\n\t * token doesn't expire\n\t *\/\n\tfunction initSessionHeartBeat() {\n\t\t\/\/ interval in seconds\n\t\tvar interval = NaN;\n\t\tif (oc_config.session_lifetime) {\n\t\t\tinterval = Math.floor(oc_config.session_lifetime \/ 2);\n\t\t}\n\t\tinterval = isNaN(interval)? 900: interval;\n\n\t\t\/\/ minimum one minute\n\t\tinterval = Math.max(60, interval);\n\t\t\/\/ max interval in seconds set to 24 hours\n\t\tinterval = Math.min(24 * 3600, interval);\n\n\t\tvar url = OC.generateUrl('\/csrftoken');\n\t\tsetInterval(function() {\n\t\t\t$.ajax(url).then(function(resp) {\n\t\t\t\toc_requesttoken = resp.token;\n\t\t\t\tOC.requestToken = resp.token;\n\t\t\t}).fail(function(e) {\n\t\t\t\tconsole.error('session heartbeat failed', e);\n\t\t\t});\n\t\t}, interval * 1000);\n\t}\n\n\t\/\/ session heartbeat (defaults to enabled)\n\tif (typeof(oc_config.session_keepalive) === 'undefined' ||\n\t\t!!oc_config.session_keepalive) {\n\n\t\tinitSessionHeartBeat();\n\t}\n\n\tOC.registerMenu($('#expand'), $('#expanddiv'), false, true);\n\n\t\/\/ toggle for menus\n\t\/\/$(document).on('mouseup.closemenus keyup', function(event) {\n\t$(document).on('mouseup.closemenus', function(event) {\n\n\t\t\/\/ allow enter as a trigger\n\t\t\/\/ if (event.key && event.key !== \"Enter\") {\n\t\t\/\/ \treturn;\n\t\t\/\/ }\n\n\t\tvar $el = $(event.target);\n\t\tif ($el.closest('.menu').length || $el.closest('.menutoggle').length) {\n\t\t\t\/\/ don't close when clicking on the menu directly or a menu toggle\n\t\t\treturn false;\n\t\t}\n\n\t\tOC.hideMenus();\n\t});\n\n\t\/**\n\t * Set up the main menu toggle to react to media query changes.\n\t * If the screen is small enough, the main menu becomes a toggle.\n\t * If the screen is bigger, the main menu is not a toggle any more.\n\t *\/\n\tfunction setupMainMenu() {\n\n\t\t\/\/ init the more-apps menu\n\t\tOC.registerMenu($('#more-apps > a'), $('#navigation'));\n\n\t\t\/\/ toggle the navigation\n\t\tvar $toggle = $('#header .header-appname-container');\n\t\tvar $navigation = $('#navigation');\n\t\tvar $appmenu = $('#appmenu');\n\n\t\t\/\/ init the menu\n\t\tOC.registerMenu($toggle, $navigation);\n\t\t$toggle.data('oldhref', $toggle.attr('href'));\n\t\t$toggle.attr('href', '#');\n\t\t$navigation.hide();\n\n\t\t\/\/ show loading feedback\n\t\t$navigation.delegate('a', 'click', function(event) {\n\t\t\tvar $app = $(event.target);\n\t\t\tif(!$app.is('a')) {\n\t\t\t\t$app = $app.closest('a');\n\t\t\t}\n\t\t\tif(event.which === 1 && !event.ctrlKey && !event.metaKey) {\n\t\t\t\t$app.addClass('app-loading');\n\t\t\t} else {\n\t\t\t\t\/\/ Close navigation when opening app in\n\t\t\t\t\/\/ a new tab\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\n\t\t$navigation.delegate('a', 'mouseup', function(event) {\n\t\t\tif(event.which === 2) {\n\t\t\t\t\/\/ Close navigation when opening app in\n\t\t\t\t\/\/ a new tab via middle click\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\n\t\t$appmenu.delegate('a', 'click', function(event) {\n\t\t\tvar $app = $(event.target);\n\t\t\tif(!$app.is('a')) {\n\t\t\t\t$app = $app.closest('a');\n\t\t\t}\n\t\t\tif(event.which === 1 && !event.ctrlKey && !event.metaKey) {\n\t\t\t\t$app.addClass('app-loading');\n\t\t\t} else {\n\t\t\t\t\/\/ Close navigation when opening app in\n\t\t\t\t\/\/ a new tab\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction setupUserMenu() {\n\t\tvar $menu = $('#header #settings');\n\n\t\t\/\/ show loading feedback\n\t\t$menu.delegate('a', 'click', function(event) {\n\t\t\tvar $page = $(event.target);\n\t\t\tif (!$page.is('a')) {\n\t\t\t\t$page = $page.closest('a');\n\t\t\t}\n\t\t\tif(event.which === 1 && !event.ctrlKey && !event.metaKey) {\n\t\t\t\t$page.find('img').remove();\n\t\t\t\t$page.find('div').remove(); \/\/ prevent odd double-clicks\n\t\t\t\t$page.prepend($('<div\/>').addClass('icon-loading-small'));\n\t\t\t} else {\n\t\t\t\t\/\/ Close navigation when opening menu entry in\n\t\t\t\t\/\/ a new tab\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\n\t\t$menu.delegate('a', 'mouseup', function(event) {\n\t\t\tif(event.which === 2) {\n\t\t\t\t\/\/ Close navigation when opening app in\n\t\t\t\t\/\/ a new tab via middle click\n\t\t\t\tOC.hideMenus(function(){return false;});\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction setupContactsMenu() {\n\t\tnew OC.ContactsMenu({\n\t\t\tel: $('#contactsmenu .menu'),\n\t\t\ttrigger: $('#contactsmenu .menutoggle')\n\t\t});\n\t}\n\n\tsetupMainMenu();\n\tsetupUserMenu();\n\tsetupContactsMenu();\n\n\t\/\/ move triangle of apps dropdown to align with app name triangle\n\t\/\/ 2 is the additional offset between the triangles\n\tif($('#navigation').length) {\n\t\t$('#header #nextcloud + .menutoggle').on('click', function(){\n\t\t\t$('#menu-css-helper').remove();\n\t\t\tvar caretPosition = $('.header-appname + .icon-caret').offset().left - 2;\n\t\t\tif(caretPosition > 255) {\n\t\t\t\t\/\/ if the app name is longer than the menu, just put the triangle in the middle\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\t$('head').append('<style id=\"menu-css-helper\">#navigation:after { left: '+ caretPosition +'px; }<\/style>');\n\t\t\t}\n\t\t});\n\t\t$('#header #appmenu .menutoggle').on('click', function() {\n\t\t\t$('#appmenu').toggleClass('menu-open');\n\t\t\tif($('#appmenu').is(':visible')) {\n\t\t\t\t$('#menu-css-helper').remove();\n\t\t\t}\n\t\t});\n\t}\n\n\tvar resizeMenu = function() {\n\t\tvar appList = $('#appmenu li');\n\t\tvar rightHeaderWidth = $('.header-right').outerWidth();\n\t\tvar headerWidth = $('header').outerWidth();\n\t\tvar usePercentualAppMenuLimit = 0.33;\n\t\tvar minAppsDesktop = 8;\n\t\tvar availableWidth =  headerWidth - $('#nextcloud').outerWidth() - (rightHeaderWidth > 210 ? rightHeaderWidth : 210)\n\t\tvar isMobile = $(window).width() < 768;\n\t\tif (!isMobile) {\n\t\t\tavailableWidth = availableWidth * usePercentualAppMenuLimit;\n\t\t}\n\t\tvar appCount = Math.floor((availableWidth \/ $(appList).width()));\n\t\tif (isMobile && appCount > minAppsDesktop) {\n\t\t\tappCount = minAppsDesktop;\n\t\t}\n\t\tif (!isMobile && appCount < minAppsDesktop) {\n\t\t\tappCount = minAppsDesktop;\n\t\t}\n\n\t\t\/\/ show at least 2 apps in the popover\n\t\tif(appList.length-1-appCount >= 1) {\n\t\t\tappCount--;\n\t\t}\n\n\t\t$('#more-apps a').removeClass('active');\n\t\tvar lastShownApp;\n\t\tfor (var k = 0; k < appList.length-1; k++) {\n\t\t\tvar name = $(appList[k]).data('id');\n\t\t\tif(k < appCount) {\n\t\t\t\t$(appList[k]).removeClass('hidden');\n\t\t\t\t$('#apps li[data-id=' + name + ']').addClass('in-header');\n\t\t\t\tlastShownApp = appList[k];\n\t\t\t} else {\n\t\t\t\t$(appList[k]).addClass('hidden');\n\t\t\t\t$('#apps li[data-id=' + name + ']').removeClass('in-header');\n\t\t\t\t\/\/ move active app to last position if it is active\n\t\t\t\tif(appCount > 0 && $(appList[k]).children('a').hasClass('active')) {\n\t\t\t\t\t$(lastShownApp).addClass('hidden');\n\t\t\t\t\t$('#apps li[data-id=' + $(lastShownApp).data('id') + ']').removeClass('in-header');\n\t\t\t\t\t$(appList[k]).removeClass('hidden');\n\t\t\t\t\t$('#apps li[data-id=' + name + ']').addClass('in-header');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t\/\/ show\/hide more apps icon\n\t\tif($('#apps li:not(.in-header)').length === 0) {\n\t\t\t$('#more-apps').hide();\n\t\t\t$('#navigation').hide();\n\t\t} else {\n\t\t\t$('#more-apps').show();\n\t\t}\n\t};\n\t$(window).resize(resizeMenu);\n\tsetTimeout(resizeMenu, 0);\n\n\t\/\/ just add snapper for logged in users\n\tif($('#app-navigation').length && !$('html').hasClass('lte9')) {\n\n\t\t\/\/ App sidebar on mobile\n\t\tvar snapper = new Snap({\n\t\t\telement: document.getElementById('app-content'),\n\t\t\tdisable: 'right',\n\t\t\tmaxPosition: 300, \/\/ $navigation-width\n\t\t\tminDragDistance: 100\n\t\t});\n\n\t\t$('#app-content').prepend('<div id=\"app-navigation-toggle\" class=\"icon-menu\" style=\"display:none;\" tabindex=\"0\"><\/div>');\n\n\t\tvar toggleSnapperOnButton = function(){\n\t\t\tif(snapper.state().state == 'left'){\n\t\t\t\tsnapper.close();\n\t\t\t} else {\n\t\t\t\tsnapper.open('left');\n\t\t\t}\n\t\t};\n\n\t\t$('#app-navigation-toggle').click(function(){\n\t\t\ttoggleSnapperOnButton();\n\t\t});\n\n\t\t$('#app-navigation-toggle').keypress(function(e) {\n\t\t\tif(e.which == 13) {\n\t\t\t\ttoggleSnapperOnButton();\n\t\t\t}\n\t\t});\n\n\t\t\/\/ close sidebar when switching navigation entry\n\t\tvar $appNavigation = $('#app-navigation');\n\t\t$appNavigation.delegate('a, :button', 'click', function(event) {\n\t\t\tvar $target = $(event.target);\n\t\t\t\/\/ don't hide navigation when changing settings or adding things\n\t\t\tif($target.is('.app-navigation-noclose') ||\n\t\t\t\t$target.closest('.app-navigation-noclose').length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif($target.is('.app-navigation-entry-utils-menu-button') ||\n\t\t\t\t$target.closest('.app-navigation-entry-utils-menu-button').length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif($target.is('.add-new') ||\n\t\t\t\t$target.closest('.add-new').length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif($target.is('#app-settings') ||\n\t\t\t\t$target.closest('#app-settings').length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsnapper.close();\n\t\t});\n\n\t\tvar navigationBarSlideGestureEnabled = false;\n\t\tvar navigationBarSlideGestureAllowed = true;\n\t\tvar navigationBarSlideGestureEnablePending = false;\n\n\t\tOC.allowNavigationBarSlideGesture = function() {\n\t\t\tnavigationBarSlideGestureAllowed = true;\n\n\t\t\tif (navigationBarSlideGestureEnablePending) {\n\t\t\t\tsnapper.enable();\n\n\t\t\t\tnavigationBarSlideGestureEnabled = true;\n\t\t\t\tnavigationBarSlideGestureEnablePending = false;\n\t\t\t}\n\t\t};\n\n\t\tOC.disallowNavigationBarSlideGesture = function() {\n\t\t\tnavigationBarSlideGestureAllowed = false;\n\n\t\t\tif (navigationBarSlideGestureEnabled) {\n\t\t\t\tvar endCurrentDrag = true;\n\t\t\t\tsnapper.disable(endCurrentDrag);\n\n\t\t\t\tnavigationBarSlideGestureEnabled = false;\n\t\t\t\tnavigationBarSlideGestureEnablePending = true;\n\t\t\t}\n\t\t};\n\n\t\tvar toggleSnapperOnSize = function() {\n\t\t\tif($(window).width() > 768) {\n\t\t\t\tsnapper.close();\n\t\t\t\tsnapper.disable();\n\n\t\t\t\tnavigationBarSlideGestureEnabled = false;\n\t\t\t\tnavigationBarSlideGestureEnablePending = false;\n\t\t\t} else if (navigationBarSlideGestureAllowed) {\n\t\t\t\tsnapper.enable();\n\n\t\t\t\tnavigationBarSlideGestureEnabled = true;\n\t\t\t\tnavigationBarSlideGestureEnablePending = false;\n\t\t\t} else {\n\t\t\t\tnavigationBarSlideGestureEnablePending = true;\n\t\t\t}\n\t\t};\n\n\t\t$(window).resize(_.debounce(toggleSnapperOnSize, 250));\n\n\t\t\/\/ initial call\n\t\ttoggleSnapperOnSize();\n\n\t}\n\n\t\/\/ Update live timestamps every 30 seconds\n\tsetInterval(function() {\n\t\t$('.live-relative-timestamp').each(function() {\n\t\t\t$(this).text(OC.Util.relativeModifiedDate(parseInt($(this).attr('data-timestamp'), 10)));\n\t\t});\n\t}, 30 * 1000);\n\n\tOC.PasswordConfirmation.init();\n}\n\nOC.PasswordConfirmation = {\n\tcallback: null,\n\tpageLoadTime: null,\n\tinit: function() {\n\t\t$('.password-confirm-required').on('click', _.bind(this.requirePasswordConfirmation, this));\n\t\tthis.pageLoadTime = moment.now();\n\t},\n\n\trequiresPasswordConfirmation: function() {\n\t\tvar serverTimeDiff = this.pageLoadTime - (nc_pageLoad * 1000);\n\t\tvar timeSinceLogin = moment.now() - (serverTimeDiff + (nc_lastLogin * 1000));\n\n\t\t\/\/ if timeSinceLogin > 30 minutes and user backend allows password confirmation\n\t\treturn (backendAllowsPasswordConfirmation && timeSinceLogin > 30 * 60 * 1000);\n\t},\n\n\t\/**\n\t * @param {function} callback\n\t *\/\n\trequirePasswordConfirmation: function(callback, options, rejectCallback) {\n\t\toptions = typeof options !== 'undefined' ? options : {};\n\t\tvar defaults = {\n\t\t\ttitle: t('core','Authentication required'),\n\t\t\ttext: t(\n\t\t\t\t'core',\n\t\t\t\t'This action requires you to confirm your password'\n\t\t\t),\n\t\t\tconfirm: t('core', 'Confirm'),\n\t\t\tlabel: t('core','Password'),\n\t\t\terror: '',\n\t\t};\n\n\t\tvar config = _.extend(defaults, options);\n\n\t\tvar self = this;\n\n\t\tif (this.requiresPasswordConfirmation()) {\n\t\t\tOC.dialogs.prompt(\n\t\t\t\tconfig.text,\n\t\t\t\tconfig.title,\n\t\t\t\tfunction (result, password) {\n\t\t\t\t\tif (result && password !== '') {\n\t\t\t\t\t\tself._confirmPassword(password, config);\n\t\t\t\t\t} else if (_.isFunction(rejectCallback)) {\n\t\t\t\t\t\trejectCallback()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\ttrue,\n\t\t\t\tconfig.label,\n\t\t\t\ttrue\n\t\t\t).then(function() {\n\t\t\t\tvar $dialog = $('.oc-dialog:visible');\n\t\t\t\t$dialog.find('.ui-icon').remove();\n\t\t\t\t$dialog.addClass('password-confirmation');\n\t\t\t\tif (config.error !== '') {\n\t\t\t\t\tvar $error = $('<p><\/p>').addClass('msg warning').text(config.error);\n\t\t\t\t}\n\t\t\t\t$dialog.find('.oc-dialog-content').append($error);\n\t\t\t\t$dialog.find('.oc-dialog-buttonrow').addClass('aside');\n\n\t\t\t\tvar $buttons = $dialog.find('button');\n\t\t\t\t$buttons.eq(0).hide();\n\t\t\t\t$buttons.eq(1).text(config.confirm);\n\t\t\t});\n\t\t}\n\n\t\tthis.callback = callback;\n\t},\n\n\t_confirmPassword: function(password, config) {\n\t\tvar self = this;\n\n\t\t$.ajax({\n\t\t\turl: OC.generateUrl('\/login\/confirm'),\n\t\t\tdata: {\n\t\t\t\tpassword: password\n\t\t\t},\n\t\t\ttype: 'POST',\n\t\t\tsuccess: function(response) {\n\t\t\t\tnc_lastLogin = response.lastLogin;\n\n\t\t\t\tif (_.isFunction(self.callback)) {\n\t\t\t\t\tself.callback();\n\t\t\t\t}\n\t\t\t},\n\t\t\terror: function() {\n\t\t\t\tconfig.error = t('core', 'Failed to authenticate, try again');\n\t\t\t\tOC.PasswordConfirmation.requirePasswordConfirmation(self.callback, config);\n\t\t\t}\n\t\t});\n\t}\n};\n\n$(document).ready(initCore);\n\n\/**\n * Filter Jquery selector by attribute value\n *\/\n$.fn.filterAttr = function(attr_name, attr_value) {\n\treturn this.filter(function() { return $(this).attr(attr_name) === attr_value; });\n};\n\n\/**\n * Returns a human readable file size\n * @param {number} size Size in bytes\n * @param {boolean} skipSmallSizes return '< 1 kB' for small files\n * @return {string}\n *\/\nfunction humanFileSize(size, skipSmallSizes) {\n\tvar humanList = ['B', 'KB', 'MB', 'GB', 'TB'];\n\t\/\/ Calculate Log with base 1024: size = 1024 ** order\n\tvar order = size > 0 ? Math.floor(Math.log(size) \/ Math.log(1024)) : 0;\n\t\/\/ Stay in range of the byte sizes that are defined\n\torder = Math.min(humanList.length - 1, order);\n\tvar readableFormat = humanList[order];\n\tvar relativeSize = (size \/ Math.pow(1024, order)).toFixed(1);\n\tif(skipSmallSizes === true && order === 0) {\n\t\tif(relativeSize !== \"0.0\"){\n\t\t\treturn '< 1 KB';\n\t\t} else {\n\t\t\treturn '0 KB';\n\t\t}\n\t}\n\tif(order < 2){\n\t\trelativeSize = parseFloat(relativeSize).toFixed(0);\n\t}\n\telse if(relativeSize.substr(relativeSize.length-2,2)==='.0'){\n\t\trelativeSize=relativeSize.substr(0,relativeSize.length-2);\n\t}\n\telse{\n\t\trelativeSize = parseFloat(relativeSize).toLocaleString(OC.getCanonicalLocale());\n\t}\n\treturn relativeSize + ' ' + readableFormat;\n}\n\n\/**\n * Format an UNIX timestamp to a human understandable format\n * @param {number} timestamp UNIX timestamp\n * @return {string} Human readable format\n *\/\nfunction formatDate(timestamp){\n\treturn OC.Util.formatDate(timestamp);\n}\n\n\/\/\n\/**\n * Get the value of a URL parameter\n * @link http:\/\/stackoverflow.com\/questions\/1403888\/get-url-parameter-with-jquery\n * @param {string} name URL parameter\n * @return {string}\n *\/\nfunction getURLParameter(name) {\n\treturn decodeURIComponent(\n\t\t(new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(\n\t\t\tlocation.search)||[,''])[1].replace(\/\\+\/g, '%20')\n\t\t)||'';\n}\n\n\/**\n * Takes an absolute timestamp and return a string with a human-friendly relative date\n * @param {number} timestamp A Unix timestamp\n *\/\nfunction relative_modified_date(timestamp) {\n\t\/*\n\t Were multiplying by 1000 to bring the timestamp back to its original value\n\t per https:\/\/github.com\/owncloud\/core\/pull\/10647#discussion_r16790315\n\t  *\/\n\treturn OC.Util.relativeModifiedDate(timestamp * 1000);\n}\n\n\/**\n * Utility functions\n * @namespace\n *\/\nOC.Util = {\n\t\/\/ TODO: remove original functions from global namespace\n\thumanFileSize: humanFileSize,\n\n\t\/**\n\t * Returns a file size in bytes from a humanly readable string\n\t * Makes 2kB to 2048.\n\t * Inspired by computerFileSize in helper.php\n\t * @param  {string} string file size in human readable format\n\t * @return {number} or null if string could not be parsed\n\t *\n\t *\n\t *\/\n\tcomputerFileSize: function (string) {\n\t\tif (typeof string !== 'string') {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar s = string.toLowerCase().trim();\n\t\tvar bytes = null;\n\n\t\tvar bytesArray = {\n\t\t\t'b' : 1,\n\t\t\t'k' : 1024,\n\t\t\t'kb': 1024,\n\t\t\t'mb': 1024 * 1024,\n\t\t\t'm' : 1024 * 1024,\n\t\t\t'gb': 1024 * 1024 * 1024,\n\t\t\t'g' : 1024 * 1024 * 1024,\n\t\t\t'tb': 1024 * 1024 * 1024 * 1024,\n\t\t\t't' : 1024 * 1024 * 1024 * 1024,\n\t\t\t'pb': 1024 * 1024 * 1024 * 1024 * 1024,\n\t\t\t'p' : 1024 * 1024 * 1024 * 1024 * 1024\n\t\t};\n\n\t\tvar matches = s.match(\/^[\\s+]?([0-9]*)(\\.([0-9]+))?( +)?([kmgtp]?b?)$\/i);\n\t\tif (matches !== null) {\n\t\t\tbytes = parseFloat(s);\n\t\t\tif (!isFinite(bytes)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t\tif (matches[5]) {\n\t\t\tbytes = bytes * bytesArray[matches[5]];\n\t\t}\n\n\t\tbytes = Math.round(bytes);\n\t\treturn bytes;\n\t},\n\n\t\/**\n\t * @param timestamp\n\t * @param format\n\t * @returns {string} timestamp formatted as requested\n\t *\/\n\tformatDate: function (timestamp, format) {\n\t\tformat = format || \"LLL\";\n\t\treturn moment(timestamp).format(format);\n\t},\n\n\t\/**\n\t * @param timestamp\n\t * @returns {string} human readable difference from now\n\t *\/\n\trelativeModifiedDate: function (timestamp) {\n\t\tvar diff = moment().diff(moment(timestamp));\n\t\tif (diff >= 0 && diff < 45000 ) {\n\t\t\treturn t('core', 'seconds ago');\n\t\t}\n\t\treturn moment(timestamp).fromNow();\n\t},\n\n\t\/**\n\t * Returns whether this is IE\n\t *\n\t * @return {bool} true if this is IE, false otherwise\n\t *\/\n\tisIE: function() {\n\t\treturn $('html').hasClass('ie');\n\t},\n\n\t\/**\n\t * Returns the width of a generic browser scrollbar\n\t *\n\t * @return {int} width of scrollbar\n\t *\/\n\tgetScrollBarWidth: function() {\n\t\tif (this._scrollBarWidth) {\n\t\t\treturn this._scrollBarWidth;\n\t\t}\n\n\t\tvar inner = document.createElement('p');\n\t\tinner.style.width = \"100%\";\n\t\tinner.style.height = \"200px\";\n\n\t\tvar outer = document.createElement('div');\n\t\touter.style.position = \"absolute\";\n\t\touter.style.top = \"0px\";\n\t\touter.style.left = \"0px\";\n\t\touter.style.visibility = \"hidden\";\n\t\touter.style.width = \"200px\";\n\t\touter.style.height = \"150px\";\n\t\touter.style.overflow = \"hidden\";\n\t\touter.appendChild (inner);\n\n\t\tdocument.body.appendChild (outer);\n\t\tvar w1 = inner.offsetWidth;\n\t\touter.style.overflow = 'scroll';\n\t\tvar w2 = inner.offsetWidth;\n\t\tif(w1 === w2) {\n\t\t\tw2 = outer.clientWidth;\n\t\t}\n\n\t\tdocument.body.removeChild (outer);\n\n\t\tthis._scrollBarWidth = (w1 - w2);\n\n\t\treturn this._scrollBarWidth;\n\t},\n\n\t\/**\n\t * Remove the time component from a given date\n\t *\n\t * @param {Date} date date\n\t * @return {Date} date with stripped time\n\t *\/\n\tstripTime: function(date) {\n\t\t\/\/ FIXME: likely to break when crossing DST\n\t\t\/\/ would be better to use a library like momentJS\n\t\treturn new Date(date.getFullYear(), date.getMonth(), date.getDate());\n\t},\n\n\t_chunkify: function(t) {\n\t\t\/\/ Adapted from http:\/\/my.opera.com\/GreyWyvern\/blog\/show.dml\/1671288\n\t\tvar tz = [], x = 0, y = -1, n = 0, code, c;\n\n\t\twhile (x < t.length) {\n\t\t\tc = t.charAt(x);\n\t\t\t\/\/ only include the dot in strings\n\t\t\tvar m = ((!n && c === '.') || (c >= '0' && c <= '9'));\n\t\t\tif (m !== n) {\n\t\t\t\t\/\/ next chunk\n\t\t\t\ty++;\n\t\t\t\ttz[y] = '';\n\t\t\t\tn = m;\n\t\t\t}\n\t\t\ttz[y] += c;\n\t\t\tx++;\n\t\t}\n\t\treturn tz;\n\t},\n\t\/**\n\t * Compare two strings to provide a natural sort\n\t * @param a first string to compare\n\t * @param b second string to compare\n\t * @return -1 if b comes before a, 1 if a comes before b\n\t * or 0 if the strings are identical\n\t *\/\n\tnaturalSortCompare: function(a, b) {\n\t\tvar x;\n\t\tvar aa = OC.Util._chunkify(a);\n\t\tvar bb = OC.Util._chunkify(b);\n\n\t\tfor (x = 0; aa[x] && bb[x]; x++) {\n\t\t\tif (aa[x] !== bb[x]) {\n\t\t\t\tvar aNum = Number(aa[x]), bNum = Number(bb[x]);\n\t\t\t\t\/\/ note: == is correct here\n\t\t\t\tif (aNum == aa[x] && bNum == bb[x]) {\n\t\t\t\t\treturn aNum - bNum;\n\t\t\t\t} else {\n\t\t\t\t\t\/\/ Note: This locale setting isn't supported by all browsers but for the ones\n\t\t\t\t\t\/\/ that do there will be more consistency between client-server sorting\n\t\t\t\t\treturn aa[x].localeCompare(bb[x], OC.getLanguage());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn aa.length - bb.length;\n\t},\n\t\/**\n\t * Calls the callback in a given interval until it returns true\n\t * @param {function} callback\n\t * @param {integer} interval in milliseconds\n\t *\/\n\twaitFor: function(callback, interval) {\n\t\tvar internalCallback = function() {\n\t\t\tif(callback() !== true) {\n\t\t\t\tsetTimeout(internalCallback, interval);\n\t\t\t}\n\t\t};\n\n\t\tinternalCallback();\n\t},\n\t\/**\n\t * Checks if a cookie with the given name is present and is set to the provided value.\n\t * @param {string} name name of the cookie\n\t * @param {string} value value of the cookie\n\t * @return {boolean} true if the cookie with the given name has the given value\n\t *\/\n\tisCookieSetToValue: function(name, value) {\n\t\tvar cookies = document.cookie.split(';');\n\t\tfor (var i=0; i < cookies.length; i++) {\n\t\t\tvar cookie = cookies[i].split('=');\n\t\t\tif (cookie[0].trim() === name && cookie[1].trim() === value) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n};\n\n\/**\n * Utility class for the history API,\n * includes fallback to using the URL hash when\n * the browser doesn't support the history API.\n *\n * @namespace\n *\/\nOC.Util.History = {\n\t_handlers: [],\n\n\t\/**\n\t * Push the current URL parameters to the history stack\n\t * and change the visible URL.\n\t * Note: this includes a workaround for IE8\/IE9 that uses\n\t * the hash part instead of the search part.\n\t *\n\t * @param {Object|string} params to append to the URL, can be either a string\n\t * or a map\n\t * @param {string} [url] URL to be used, otherwise the current URL will be used,\n\t * using the params as query string\n\t * @param {boolean} [replace=false] whether to replace instead of pushing\n\t *\/\n\t_pushState: function(params, url, replace) {\n\t\tvar strParams;\n\t\tif (typeof(params) === 'string') {\n\t\t\tstrParams = params;\n\t\t}\n\t\telse {\n\t\t\tstrParams = OC.buildQueryString(params);\n\t\t}\n\t\tif (window.history.pushState) {\n\t\t\turl = url || location.pathname + '?' + strParams;\n\t\t\t\/\/ Workaround for bug with SVG and window.history.pushState on Firefox < 51\n\t\t\t\/\/ https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=652991\n\t\t\tvar isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;\n\t\t\tif (isFirefox && parseInt(navigator.userAgent.split('\/').pop()) < 51) {\n\t\t\t\tvar patterns = document.querySelectorAll('[fill^=\"url(#\"], [stroke^=\"url(#\"], [filter^=\"url(#invert\"]');\n\t\t\t\tfor (var i = 0, ii = patterns.length, pattern; i < ii; i++) {\n\t\t\t\t\tpattern = patterns[i];\n\t\t\t\t\tpattern.style.fill = pattern.style.fill;\n\t\t\t\t\tpattern.style.stroke = pattern.style.stroke;\n\t\t\t\t\tpattern.removeAttribute(\"filter\");\n\t\t\t\t\tpattern.setAttribute(\"filter\", \"url(#invert)\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (replace) {\n\t\t\t\twindow.history.replaceState(params, '', url);\n\t\t\t} else {\n\t\t\t\twindow.history.pushState(params, '', url);\n\t\t\t}\n\t\t}\n\t\t\/\/ use URL hash for IE8\n\t\telse {\n\t\t\twindow.location.hash = '?' + strParams;\n\t\t\t\/\/ inhibit next onhashchange that just added itself\n\t\t\t\/\/ to the event queue\n\t\t\tthis._cancelPop = true;\n\t\t}\n\t},\n\n\t\/**\n\t * Push the current URL parameters to the history stack\n\t * and change the visible URL.\n\t * Note: this includes a workaround for IE8\/IE9 that uses\n\t * the hash part instead of the search part.\n\t *\n\t * @param {Object|string} params to append to the URL, can be either a string\n\t * or a map\n\t * @param {string} [url] URL to be used, otherwise the current URL will be used,\n\t * using the params as query string\n\t *\/\n\tpushState: function(params, url) {\n\t\treturn this._pushState(params, url, false);\n\t},\n\n\t\/**\n\t * Push the current URL parameters to the history stack\n\t * and change the visible URL.\n\t * Note: this includes a workaround for IE8\/IE9 that uses\n\t * the hash part instead of the search part.\n\t *\n\t * @param {Object|string} params to append to the URL, can be either a string\n\t * or a map\n\t * @param {string} [url] URL to be used, otherwise the current URL will be used,\n\t * using the params as query string\n\t *\/\n\treplaceState: function(params, url) {\n\t\treturn this._pushState(params, url, true);\n\t},\n\n\t\/**\n\t * Add a popstate handler\n\t *\n\t * @param handler function\n\t *\/\n\taddOnPopStateHandler: function(handler) {\n\t\tthis._handlers.push(handler);\n\t},\n\n\t\/**\n\t * Parse a query string from the hash part of the URL.\n\t * (workaround for IE8 \/ IE9)\n\t *\/\n\t_parseHashQuery: function() {\n\t\tvar hash = window.location.hash,\n\t\t\tpos = hash.indexOf('?');\n\t\tif (pos >= 0) {\n\t\t\treturn hash.substr(pos + 1);\n\t\t}\n\t\tif (hash.length) {\n\t\t\t\/\/ remove hash sign\n\t\t\treturn hash.substr(1);\n\t\t}\n\t\treturn '';\n\t},\n\n\t_decodeQuery: function(query) {\n\t\treturn query.replace(\/\\+\/g, ' ');\n\t},\n\n\t\/**\n\t * Parse the query\/search part of the URL.\n\t * Also try and parse it from the URL hash (for IE8)\n\t *\n\t * @return map of parameters\n\t *\/\n\tparseUrlQuery: function() {\n\t\tvar query = this._parseHashQuery(),\n\t\t\tparams;\n\t\t\/\/ try and parse from URL hash first\n\t\tif (query) {\n\t\t\tparams = OC.parseQueryString(this._decodeQuery(query));\n\t\t}\n\t\t\/\/ else read from query attributes\n\t\tparams = _.extend(params || {}, OC.parseQueryString(this._decodeQuery(location.search)));\n\t\treturn params || {};\n\t},\n\n\t_onPopState: function(e) {\n\t\tif (this._cancelPop) {\n\t\t\tthis._cancelPop = false;\n\t\t\treturn;\n\t\t}\n\t\tvar params;\n\t\tif (!this._handlers.length) {\n\t\t\treturn;\n\t\t}\n\t\tparams = (e && e.state);\n\t\tif (_.isString(params)) {\n\t\t\tparams = OC.parseQueryString(params);\n\t\t} else if (!params) {\n\t\t\tparams = this.parseUrlQuery() || {};\n\t\t}\n\t\tfor (var i = 0; i < this._handlers.length; i++) {\n\t\t\tthis._handlers[i](params);\n\t\t}\n\t}\n};\n\n\/\/ fallback to hashchange when no history support\nif (window.history.pushState) {\n\twindow.onpopstate = _.bind(OC.Util.History._onPopState, OC.Util.History);\n}\nelse {\n\t$(window).on('hashchange', _.bind(OC.Util.History._onPopState, OC.Util.History));\n}\n\n\/**\n * Get a variable by name\n * @param {string} name\n * @return {*}\n *\/\nOC.get=function(name) {\n\tvar namespaces = name.split(\".\");\n\tvar tail = namespaces.pop();\n\tvar context=window;\n\n\tfor(var i = 0; i < namespaces.length; i++) {\n\t\tcontext = context[namespaces[i]];\n\t\tif(!context){\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn context[tail];\n};\n\n\/**\n * Set a variable by name\n * @param {string} name\n * @param {*} value\n *\/\nOC.set=function(name, value) {\n\tvar namespaces = name.split(\".\");\n\tvar tail = namespaces.pop();\n\tvar context=window;\n\n\tfor(var i = 0; i < namespaces.length; i++) {\n\t\tif(!context[namespaces[i]]){\n\t\t\tcontext[namespaces[i]]={};\n\t\t}\n\t\tcontext = context[namespaces[i]];\n\t}\n\tcontext[tail]=value;\n};\n\n\/\/ fix device width on windows phone\n(function() {\n\tif (\"-ms-user-select\" in document.documentElement.style && navigator.userAgent.match(\/IEMobile\\\/10\\.0\/)) {\n\t\tvar msViewportStyle = document.createElement(\"style\");\n\t\tmsViewportStyle.appendChild(\n\t\t\tdocument.createTextNode(\"@-ms-viewport{width:auto!important}\")\n\t\t);\n\t\tdocument.getElementsByTagName(\"head\")[0].appendChild(msViewportStyle);\n\t}\n})();\n\n\/**\n * Namespace for apps\n * @namespace OCA\n *\/\nwindow.OCA = {};\n\n\/**\n * select a range in an input field\n * @link http:\/\/stackoverflow.com\/questions\/499126\/jquery-set-cursor-position-in-text-area\n * @param {type} start\n * @param {type} end\n *\/\njQuery.fn.selectRange = function(start, end) {\n\treturn this.each(function() {\n\t\tif (this.setSelectionRange) {\n\t\t\tthis.focus();\n\t\t\tthis.setSelectionRange(start, end);\n\t\t} else if (this.createTextRange) {\n\t\t\tvar range = this.createTextRange();\n\t\t\trange.collapse(true);\n\t\t\trange.moveEnd('character', end);\n\t\t\trange.moveStart('character', start);\n\t\t\trange.select();\n\t\t}\n\t});\n};\n\n\/**\n * check if an element exists.\n * allows you to write if ($('#myid').exists()) to increase readability\n * @link http:\/\/stackoverflow.com\/questions\/31044\/is-there-an-exists-function-for-jquery\n *\/\njQuery.fn.exists = function(){\n\treturn this.length > 0;\n};\n\n\/**\n * jQuery tipsy shim for the bootstrap tooltip\n *\/\njQuery.fn.tipsy = function(argument) {\n\tconsole.warn('Deprecation warning: tipsy is deprecated. Use tooltip instead.');\n\tif(typeof argument === 'object' && argument !== null) {\n\n\t\t\/\/ tipsy defaults\n\t\tvar options = {\n\t\t\tplacement: 'bottom',\n\t\t\tdelay: { 'show': 0, 'hide': 0},\n\t\t\ttrigger: 'hover',\n\t\t\thtml: false,\n\t\t\tcontainer: 'body'\n\t\t};\n\t\tif(argument.gravity) {\n\t\t\tswitch(argument.gravity) {\n\t\t\t\tcase 'n':\n\t\t\t\tcase 'nw':\n\t\t\t\tcase 'ne':\n\t\t\t\t\toptions.placement='bottom';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 's':\n\t\t\t\tcase 'sw':\n\t\t\t\tcase 'se':\n\t\t\t\t\toptions.placement='top';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'w':\n\t\t\t\t\toptions.placement='right';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'e':\n\t\t\t\t\toptions.placement='left';\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif(argument.trigger) {\n\t\t\toptions.trigger = argument.trigger;\n\t\t}\n\t\tif(argument.delayIn) {\n\t\t\toptions.delay.show = argument.delayIn;\n\t\t}\n\t\tif(argument.delayOut) {\n\t\t\toptions.delay.hide = argument.delayOut;\n\t\t}\n\t\tif(argument.html) {\n\t\t\toptions.html = true;\n\t\t}\n\t\tif(argument.fallback) {\n\t\t\toptions.title = argument.fallback;\n\t\t}\n\t\t\/\/ destroy old tooltip in case the title has changed\n\t\tjQuery.fn.tooltip.call(this, 'destroy');\n\t\tjQuery.fn.tooltip.call(this, options);\n\t} else {\n\t\tthis.tooltip(argument);\n\t\tjQuery.fn.tooltip.call(this, argument);\n\t}\n\treturn this;\n};\n\n\n\/**\n * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com>\n *\n * This file is licensed under the Affero General Public License version 3\n * or later.\n *\n * See the COPYING-README file.\n *\n *\/\n\n\/**\n * L10N namespace with localization functions.\n *\n * @namespace\n *\/\nOC.L10N = {\n\t\/**\n\t * String bundles with app name as key.\n\t * @type {Object.<String,String>}\n\t *\/\n\t_bundles: {},\n\n\t\/**\n\t * Plural functions, key is app name and value is function.\n\t * @type {Object.<String,Function>}\n\t *\/\n\t_pluralFunctions: {},\n\n\t\/**\n\t * Load an app's translation bundle if not loaded already.\n\t *\n\t * @param {String} appName name of the app\n\t * @param {Function} callback callback to be called when\n\t * the translations are loaded\n\t * @return {Promise} promise\n\t *\/\n\tload: function(appName, callback) {\n\t\t\/\/ already available ?\n\t\tif (this._bundles[appName] || OC.getLocale() === 'en') {\n\t\t\tvar deferred = $.Deferred();\n\t\t\tvar promise = deferred.promise();\n\t\t\tpromise.then(callback);\n\t\t\tdeferred.resolve();\n\t\t\treturn promise;\n\t\t}\n\n\t\tvar self = this;\n\t\tvar url = OC.filePath(appName, 'l10n', OC.getLocale() + '.json');\n\n\t\t\/\/ load JSON translation bundle per AJAX\n\t\treturn $.get(url)\n\t\t\t.then(\n\t\t\t\tfunction(result) {\n\t\t\t\t\tif (result.translations) {\n\t\t\t\t\t\tself.register(appName, result.translations, result.pluralForm);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.then(callback);\n\t},\n\n\t\/**\n\t * Register an app's translation bundle.\n\t *\n\t * @param {String} appName name of the app\n\t * @param {Object<String,String>} bundle\n\t * @param {Function|String} [pluralForm] optional plural function or plural string\n\t *\/\n\tregister: function(appName, bundle, pluralForm) {\n\t\tvar self = this;\n\t\tif (_.isUndefined(this._bundles[appName])) {\n\t\t\tthis._bundles[appName] = bundle || {};\n\n\t\t\t\/\/ generate plural function based on form\n\t\t\tthis._pluralFunctions[appName] = this._getPlural;\n\t\t} else {\n\t\t\t\/\/ Theme overwriting the default language\n\t\t\t_.extend(self._bundles[appName], bundle);\n\t\t}\n\t},\n\n\t\/**\n\t * Translate a string\n\t * @param {string} app the id of the app for which to translate the string\n\t * @param {string} text the string to translate\n\t * @param [vars] map of placeholder key to value\n\t * @param {number} [count] number to replace %n with\n\t * @param {array} [options] options array\n\t * @param {bool} [options.escape=true] enable\/disable auto escape of placeholders (by default enabled)\n\t * @return {string}\n\t *\/\n\ttranslate: function(app, text, vars, count, options) {\n\t\tvar defaultOptions = {\n\t\t\t\tescape: true\n\t\t\t},\n\t\t\tallOptions = options || {};\n\t\t_.defaults(allOptions, defaultOptions);\n\n\t\t\/\/ TODO: cache this function to avoid inline recreation\n\t\t\/\/ of the same function over and over again in case\n\t\t\/\/ translate() is used in a loop\n\t\tvar _build = function (text, vars, count) {\n\t\t\treturn text.replace(\/%n\/g, count).replace(\/{([^{}]*)}\/g,\n\t\t\t\tfunction (a, b) {\n\t\t\t\t\tvar r = vars[b];\n\t\t\t\t\tif(typeof r === 'string' || typeof r === 'number') {\n\t\t\t\t\t\tif(allOptions.escape) {\n\t\t\t\t\t\t\treturn DOMPurify.sanitize(escapeHTML(r));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn DOMPurify.sanitize(r);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn DOMPurify.sanitize(a);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\t\t};\n\t\tvar translation = text;\n\t\tvar bundle = this._bundles[app] || {};\n\t\tvar value = bundle[text];\n\t\tif( typeof(value) !== 'undefined' ){\n\t\t\ttranslation = value;\n\t\t}\n\n\t\tif(typeof vars === 'object' || count !== undefined ) {\n\t\t\treturn DOMPurify.sanitize(_build(translation, vars, count));\n\t\t} else {\n\t\t\treturn DOMPurify.sanitize(translation);\n\t\t}\n\t},\n\n\t\/**\n\t * Translate a plural string\n\t * @param {string} app the id of the app for which to translate the string\n\t * @param {string} textSingular the string to translate for exactly one object\n\t * @param {string} textPlural the string to translate for n objects\n\t * @param {number} count number to determine whether to use singular or plural\n\t * @param [vars] map of placeholder key to value\n\t * @param {array} [options] options array\n\t * @param {bool} [options.escape=true] enable\/disable auto escape of placeholders (by default enabled)\n\t * @return {string} Translated string\n\t *\/\n\ttranslatePlural: function(app, textSingular, textPlural, count, vars, options) {\n\t\tvar identifier = '_' + textSingular + '_::_' + textPlural + '_';\n\t\tvar bundle = this._bundles[app] || {};\n\t\tvar value = bundle[identifier];\n\t\tif( typeof(value) !== 'undefined' ){\n\t\t\tvar translation = value;\n\t\t\tif ($.isArray(translation)) {\n\t\t\t\tvar plural = this._pluralFunctions[app](count);\n\t\t\t\treturn this.translate(app, translation[plural], vars, count, options);\n\t\t\t}\n\t\t}\n\n\t\tif(count === 1) {\n\t\t\treturn this.translate(app, textSingular, vars, count, options);\n\t\t}\n\t\telse{\n\t\t\treturn this.translate(app, textPlural, vars, count, options);\n\t\t}\n\t},\n\n\t\/**\n\t * The plural function taken from symfony\n\t *\n\t * @param {number} number\n\t * @returns {number}\n\t * @private\n\t *\/\n\t_getPlural: function(number) {\n\t\tvar locale = OC.getLocale();\n\t\tif ('pt_BR' === locale) {\n\t\t\t\/\/ temporary set a locale for brazilian\n\t\t\tlocale = 'xbr';\n\t\t}\n\n\t\tif (typeof locale === 'undefined') {\n\t\t\treturn (1 == number) ? 0 : 1;\n\t\t}\n\n\t\tif (locale.length > 3) {\n\t\t\tlocale = locale.substring(0, locale.lastIndexOf('_'));\n\t\t}\n\n\t\t\/*\n\t\t * The plural rules are derived from code of the Zend Framework (2010-09-25),\n\t\t * which is subject to the new BSD license (http:\/\/framework.zend.com\/license\/new-bsd).\n\t\t * Copyright (c) 2005-2010 Zend Technologies USA Inc. (http:\/\/www.zend.com)\n\t\t *\/\n\t\tswitch (locale) {\n\t\t\tcase 'az':\n\t\t\tcase 'bo':\n\t\t\tcase 'dz':\n\t\t\tcase 'id':\n\t\t\tcase 'ja':\n\t\t\tcase 'jv':\n\t\t\tcase 'ka':\n\t\t\tcase 'km':\n\t\t\tcase 'kn':\n\t\t\tcase 'ko':\n\t\t\tcase 'ms':\n\t\t\tcase 'th':\n\t\t\tcase 'tr':\n\t\t\tcase 'vi':\n\t\t\tcase 'zh':\n\t\t\t\treturn 0;\n\n\t\t\tcase 'af':\n\t\t\tcase 'bn':\n\t\t\tcase 'bg':\n\t\t\tcase 'ca':\n\t\t\tcase 'da':\n\t\t\tcase 'de':\n\t\t\tcase 'el':\n\t\t\tcase 'en':\n\t\t\tcase 'eo':\n\t\t\tcase 'es':\n\t\t\tcase 'et':\n\t\t\tcase 'eu':\n\t\t\tcase 'fa':\n\t\t\tcase 'fi':\n\t\t\tcase 'fo':\n\t\t\tcase 'fur':\n\t\t\tcase 'fy':\n\t\t\tcase 'gl':\n\t\t\tcase 'gu':\n\t\t\tcase 'ha':\n\t\t\tcase 'he':\n\t\t\tcase 'hu':\n\t\t\tcase 'is':\n\t\t\tcase 'it':\n\t\t\tcase 'ku':\n\t\t\tcase 'lb':\n\t\t\tcase 'ml':\n\t\t\tcase 'mn':\n\t\t\tcase 'mr':\n\t\t\tcase 'nah':\n\t\t\tcase 'nb':\n\t\t\tcase 'ne':\n\t\t\tcase 'nl':\n\t\t\tcase 'nn':\n\t\t\tcase 'no':\n\t\t\tcase 'oc':\n\t\t\tcase 'om':\n\t\t\tcase 'or':\n\t\t\tcase 'pa':\n\t\t\tcase 'pap':\n\t\t\tcase 'ps':\n\t\t\tcase 'pt':\n\t\t\tcase 'so':\n\t\t\tcase 'sq':\n\t\t\tcase 'sv':\n\t\t\tcase 'sw':\n\t\t\tcase 'ta':\n\t\t\tcase 'te':\n\t\t\tcase 'tk':\n\t\t\tcase 'ur':\n\t\t\tcase 'zu':\n\t\t\t\treturn (1 == number) ? 0 : 1;\n\n\t\t\tcase 'am':\n\t\t\tcase 'bh':\n\t\t\tcase 'fil':\n\t\t\tcase 'fr':\n\t\t\tcase 'gun':\n\t\t\tcase 'hi':\n\t\t\tcase 'hy':\n\t\t\tcase 'ln':\n\t\t\tcase 'mg':\n\t\t\tcase 'nso':\n\t\t\tcase 'xbr':\n\t\t\tcase 'ti':\n\t\t\tcase 'wa':\n\t\t\t\treturn ((0 == number) || (1 == number)) ? 0 : 1;\n\n\t\t\tcase 'be':\n\t\t\tcase 'bs':\n\t\t\tcase 'hr':\n\t\t\tcase 'ru':\n\t\t\tcase 'sh':\n\t\t\tcase 'sr':\n\t\t\tcase 'uk':\n\t\t\t\treturn ((1 == number % 10) && (11 != number % 100)) ? 0 : (((number % 10 >= 2) && (number % 10 <= 4) && ((number % 100 < 10) || (number % 100 >= 20))) ? 1 : 2);\n\n\t\t\tcase 'cs':\n\t\t\tcase 'sk':\n\t\t\t\treturn (1 == number) ? 0 : (((number >= 2) && (number <= 4)) ? 1 : 2);\n\n\t\t\tcase 'ga':\n\t\t\t\treturn (1 == number) ? 0 : ((2 == number) ? 1 : 2);\n\n\t\t\tcase 'lt':\n\t\t\t\treturn ((1 == number % 10) && (11 != number % 100)) ? 0 : (((number % 10 >= 2) && ((number % 100 < 10) || (number % 100 >= 20))) ? 1 : 2);\n\n\t\t\tcase 'sl':\n\t\t\t\treturn (1 == number % 100) ? 0 : ((2 == number % 100) ? 1 : (((3 == number % 100) || (4 == number % 100)) ? 2 : 3));\n\n\t\t\tcase 'mk':\n\t\t\t\treturn (1 == number % 10) ? 0 : 1;\n\n\t\t\tcase 'mt':\n\t\t\t\treturn (1 == number) ? 0 : (((0 == number) || ((number % 100 > 1) && (number % 100 < 11))) ? 1 : (((number % 100 > 10) && (number % 100 < 20)) ? 2 : 3));\n\n\t\t\tcase 'lv':\n\t\t\t\treturn (0 == number) ? 0 : (((1 == number % 10) && (11 != number % 100)) ? 1 : 2);\n\n\t\t\tcase 'pl':\n\t\t\t\treturn (1 == number) ? 0 : (((number % 10 >= 2) && (number % 10 <= 4) && ((number % 100 < 12) || (number % 100 > 14))) ? 1 : 2);\n\n\t\t\tcase 'cy':\n\t\t\t\treturn (1 == number) ? 0 : ((2 == number) ? 1 : (((8 == number) || (11 == number)) ? 2 : 3));\n\n\t\t\tcase 'ro':\n\t\t\t\treturn (1 == number) ? 0 : (((0 == number) || ((number % 100 > 0) && (number % 100 < 20))) ? 1 : 2);\n\n\t\t\tcase 'ar':\n\t\t\t\treturn (0 == number) ? 0 : ((1 == number) ? 1 : ((2 == number) ? 2 : (((number % 100 >= 3) && (number % 100 <= 10)) ? 3 : (((number % 100 >= 11) && (number % 100 <= 99)) ? 4 : 5))));\n\n\t\t\tdefault:\n\t\t\t\treturn 0;\n\t\t}\n\t}\n};\n\n\/**\n * translate a string\n * @param {string} app the id of the app for which to translate the string\n * @param {string} text the string to translate\n * @param [vars] map of placeholder key to value\n * @param {number} [count] number to replace %n with\n * @return {string}\n *\/\nwindow.t = _.bind(OC.L10N.translate, OC.L10N);\n\n\/**\n * translate a string\n * @param {string} app the id of the app for which to translate the string\n * @param {string} text_singular the string to translate for exactly one object\n * @param {string} text_plural the string to translate for n objects\n * @param {number} count number to determine whether to use singular or plural\n * @param [vars] map of placeholder key to value\n * @return {string} Translated string\n *\/\nwindow.n = _.bind(OC.L10N.translatePlural, OC.L10N);\n\nHandlebars.registerHelper('t', function(app, text) {\n\treturn OC.L10N.translate(app, text);\n});\n\n\n\n\/**\n * jQuery plugin for micro templates\n *\n * Strings are automatically escaped, but that can be disabled by setting\n * escapeFunction to null.\n *\n * Usage examples:\n *\n *\tvar htmlStr = '<p>Bake, uncovered, until the {greasystuff} is melted and the {pasta} is heated through, about {min} minutes.<\/p>'\n *\t$(htmlStr).octemplate({greasystuff: 'cheese', pasta: 'macaroni', min: 10});\n *\n * \tvar htmlStr = '<p>Welcome back {user}<\/p>';\n *\t$(htmlStr).octemplate({user: 'John Q. Public'}, {escapeFunction: null});\n *\n * Be aware that the target string must be wrapped in an HTML element for the\n * plugin to work. The following won't work:\n * \n *      var textStr = 'Welcome back {user}';\n *      $(textStr).octemplate({user: 'John Q. Public'});\n *\n * For anything larger than one-liners, you can use a simple $.get() ajax\n * request to get the template, or you can embed them it the page using the\n * text\/template type:\n *\n * <script id=\"contactListItemTemplate\" type=\"text\/template\">\n *\t<tr class=\"contact\" data-id=\"{id}\">\n *\t\t<td class=\"name\">\n *\t\t\t<input type=\"checkbox\" name=\"id\" value=\"{id}\" \/><span class=\"nametext\">{name}<\/span>\n *\t\t<\/td>\n *\t\t<td class=\"email\">\n *\t\t\t<a href=\"mailto:{email}\">{email}<\/a>\n *\t\t<\/td>\n *\t\t<td class=\"phone\">{phone}<\/td>\n *\t<\/tr>\n * <\/script>\n *\n * var $tmpl = $('#contactListItemTemplate');\n * var contacts = \/\/ fetched in some ajax call\n *\n * $.each(contacts, function(idx, contact) {\n * \t\t$contactList.append(\n * \t\t\t$tmpl.octemplate({\n * \t\t\t\tid: contact.getId(),\n * \t\t\t\tname: contact.getDisplayName(),\n * \t\t\t\temail: contact.getPreferredEmail(),\n * \t\t\t\tphone: contact.getPreferredPhone(),\n * \t\t\t});\n * \t\t);\n * });\n *\/\n(function( $ ) {\n\t\/**\n\t* Object Template\n\t* Inspired by micro templating done by e.g. underscore.js\n\t*\/\n\tvar Template = {\n\t\tinit: function(vars, options, elem) {\n\t\t\t\/\/ Mix in the passed in options with the default options\n\t\t\tthis.vars = vars;\n\t\t\tthis.options = $.extend({},this.options,options);\n\n\t\t\tthis.elem = elem;\n\t\t\tvar self = this;\n\n\t\t\tif(typeof this.options.escapeFunction === 'function') {\n\t\t\t\tvar keys = Object.keys(this.vars);\n\t\t\t\tfor (var key = 0; key < keys.length; key++) {\n\t\t\t\t\tif(typeof this.vars[keys[key]] === 'string') {\n\t\t\t\t\t\tthis.vars[keys[key]] = self.options.escapeFunction(this.vars[keys[key]]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar _html = this._build(this.vars);\n\t\t\treturn $(_html);\n\t\t},\n\t\t\/\/ From stackoverflow.com\/questions\/1408289\/best-way-to-do-variable-interpolation-in-javascript\n\t\t_build: function(o){\n\t\t\tvar data = this.elem.attr('type') === 'text\/template' ? this.elem.html() : this.elem.get(0).outerHTML;\n\t\t\ttry {\n\t\t\t\treturn data.replace(\/{([^{}]*)}\/g,\n\t\t\t\t\tfunction (a, b) {\n\t\t\t\t\t\tvar r = o[b];\n\t\t\t\t\t\treturn typeof r === 'string' || typeof r === 'number' ? r : a;\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} catch(e) {\n\t\t\t\tconsole.error(e, 'data:', data);\n\t\t\t}\n\t\t},\n\t\toptions: {\n\t\t\tescapeFunction: escapeHTML\n\t\t}\n\t};\n\n\t$.fn.octemplate = function(vars, options) {\n\t\tvars = vars || {};\n\t\tif(this.length) {\n\t\t\tvar _template = Object.create(Template);\n\t\t\treturn _template.init(vars, options, this);\n\t\t}\n\t};\n\n})( jQuery );\n\n\n\n\/**\n * ownCloud\n *\n * @author Robin Appelman\n * @copyright 2012 Robin Appelman icewind1991@gmail.com\n *\n * This library is free software; you can redistribute it and\/or\n * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library 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\n * License along with this library.  If not, see <http:\/\/www.gnu.org\/licenses\/>.\n *\n *\/\n\n\/**\n * Wrapper for server side events\n * (http:\/\/en.wikipedia.org\/wiki\/Server-sent_events)\n * includes a fallback for older browsers and IE\n *\n * use server side events with caution, too many open requests can hang the\n * server\n *\/\n\n\/* global EventSource *\/\n\n\/**\n * Create a new event source\n * @param {string} src\n * @param {object} [data] to be send as GET\n *\n * @constructs OC.EventSource\n *\/\nOC.EventSource=function(src,data){\n\tvar dataStr='';\n\tvar name;\n\tvar joinChar;\n\tthis.typelessListeners=[];\n\tthis.closed = false;\n\tthis.listeners={};\n\tif(data){\n\t\tfor(name in data){\n\t\t\tdataStr+=name+'='+encodeURIComponent(data[name])+'&';\n\t\t}\n\t}\n\tdataStr+='requesttoken='+encodeURIComponent(oc_requesttoken);\n\tif(!this.useFallBack && typeof EventSource !== 'undefined'){\n\t\tjoinChar = '&';\n\t\tif(src.indexOf('?') === -1) {\n\t\t\tjoinChar = '?';\n\t\t}\n\t\tthis.source= new EventSource(src+joinChar+dataStr);\n\t\tthis.source.onmessage=function(e){\n\t\t\tfor(var i=0;i<this.typelessListeners.length;i++){\n\t\t\t\tthis.typelessListeners[i](JSON.parse(e.data));\n\t\t\t}\n\t\t}.bind(this);\n\t}else{\n\t\tvar iframeId='oc_eventsource_iframe_'+OC.EventSource.iframeCount;\n\t\tOC.EventSource.fallBackSources[OC.EventSource.iframeCount]=this;\n\t\tthis.iframe=$('<iframe\/>');\n\t\tthis.iframe.attr('id',iframeId);\n\t\tthis.iframe.hide();\n\n\t\tjoinChar = '&';\n\t\tif(src.indexOf('?') === -1) {\n\t\t\tjoinChar = '?';\n\t\t}\n\t\tthis.iframe.attr('src',src+joinChar+'fallback=true&fallback_id='+OC.EventSource.iframeCount+'&'+dataStr);\n\t\t$('body').append(this.iframe);\n\t\tthis.useFallBack=true;\n\t\tOC.EventSource.iframeCount++;\n\t}\n\t\/\/add close listener\n\tthis.listen('__internal__',function(data){\n\t\tif(data === 'close'){\n\t\t\tthis.close();\n\t\t}\n\t}.bind(this));\n};\nOC.EventSource.fallBackSources=[];\nOC.EventSource.iframeCount=0;\/\/number of fallback iframes\nOC.EventSource.fallBackCallBack=function(id,type,data){\n\tOC.EventSource.fallBackSources[id].fallBackCallBack(type,data);\n};\nOC.EventSource.prototype={\n\ttypelessListeners:[],\n\tiframe:null,\n\tlisteners:{},\/\/only for fallback\n\tuseFallBack:false,\n\t\/**\n\t * Fallback callback for browsers that don't have the\n\t * native EventSource object.\n\t *\n\t * Calls the registered listeners.\n\t *\n\t * @private\n\t * @param {String} type event type\n\t * @param {Object} data received data\n\t *\/\n\tfallBackCallBack:function(type,data){\n\t\tvar i;\n\t\t\/\/ ignore messages that might appear after closing\n\t\tif (this.closed) {\n\t\t\treturn;\n\t\t}\n\t\tif(type){\n\t\t\tif (typeof this.listeners.done !== 'undefined') {\n\t\t\t\tfor(i=0;i<this.listeners[type].length;i++){\n\t\t\t\t\tthis.listeners[type][i](data);\n\t\t\t\t}\n\t\t\t}\n\t\t}else{\n\t\t\tfor(i=0;i<this.typelessListeners.length;i++){\n\t\t\t\tthis.typelessListeners[i](data);\n\t\t\t}\n\t\t}\n\t},\n\tlastLength:0,\/\/for fallback\n\t\/**\n\t * Listen to a given type of events.\n\t *\n\t * @param {String} type event type\n\t * @param {Function} callback event callback\n\t *\/\n\tlisten:function(type,callback){\n\t\tif(callback && callback.call){\n\n\t\t\tif(type){\n\t\t\t\tif(this.useFallBack){\n\t\t\t\t\tif(!this.listeners[type]){\n\t\t\t\t\t\tthis.listeners[type]=[];\n\t\t\t\t\t}\n\t\t\t\t\tthis.listeners[type].push(callback);\n\t\t\t\t}else{\n\t\t\t\t\tthis.source.addEventListener(type,function(e){\n\t\t\t\t\t\tif (typeof e.data !== 'undefined') {\n\t\t\t\t\t\t\tcallback(JSON.parse(e.data));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcallback('');\n\t\t\t\t\t\t}\n\t\t\t\t\t},false);\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tthis.typelessListeners.push(callback);\n\t\t\t}\n\t\t}\n\t},\n\t\/**\n\t * Closes this event source.\n\t *\/\n\tclose:function(){\n\t\tthis.closed = true;\n\t\tif (typeof this.source !== 'undefined') {\n\t\t\tthis.source.close();\n\t\t}\n\t}\n};\n\n\n\/**\n * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com>\n *\n * @license GNU AGPL version 3 or any later version\n *\n * This program is free software: you can redistribute it and\/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program 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 this program.  If not, see <http:\/\/www.gnu.org\/licenses\/>.\n *\n *\/\n\n\/**\n * @namespace\n * @since 11.0.0\n *\/\nOCP.AppConfig = {\n\t\/**\n\t * @param {string} method\n\t * @param {string} endpoint\n\t * @param {Object} [options]\n\t * @param {Object} [options.data]\n\t * @param {function} [options.success]\n\t * @param {function} [options.error]\n\t * @internal\n\t *\/\n\t_call: function(method, endpoint, options) {\n\t\tif ((method === 'post' || method === 'delete') && OC.PasswordConfirmation.requiresPasswordConfirmation()) {\n\t\t\tOC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this._call, this, method, endpoint, options));\n\t\t\treturn;\n\t\t}\n\n\t\toptions = options || {};\n\t\t$.ajax({\n\t\t\ttype: method.toUpperCase(),\n\t\t\turl: OC.linkToOCS('apps\/provisioning_api\/api\/v1', 2) + 'config\/apps' + endpoint,\n\t\t\tdata: options.data || {},\n\t\t\tsuccess: options.success,\n\t\t\terror: options.error\n\t\t});\n\t},\n\n\t\/**\n\t * @param {Object} [options]\n\t * @param {function} [options.success]\n\t * @since 11.0.0\n\t *\/\n\tgetApps: function(options) {\n\t\tthis._call('get', '', options);\n\t},\n\n\t\/**\n\t * @param {string} app\n\t * @param {Object} [options]\n\t * @param {function} [options.success]\n\t * @param {function} [options.error]\n\t * @since 11.0.0\n\t *\/\n\tgetKeys: function(app, options) {\n\t\tthis._call('get', '\/' + app, options);\n\t},\n\n\t\/**\n\t * @param {string} app\n\t * @param {string} key\n\t * @param {string|function} defaultValue\n\t * @param {Object} [options]\n\t * @param {function} [options.success]\n\t * @param {function} [options.error]\n\t * @since 11.0.0\n\t *\/\n\tgetValue: function(app, key, defaultValue, options) {\n\t\toptions = options || {};\n\t\toptions.data = {\n\t\t\tdefaultValue: defaultValue\n\t\t};\n\n\t\tthis._call('get', '\/' + app + '\/' + key, options);\n\t},\n\n\t\/**\n\t * @param {string} app\n\t * @param {string} key\n\t * @param {string} value\n\t * @param {Object} [options]\n\t * @param {function} [options.success]\n\t * @param {function} [options.error]\n\t * @since 11.0.0\n\t *\/\n\tsetValue: function(app, key, value, options) {\n\t\toptions = options || {};\n\t\toptions.data = {\n\t\t\tvalue: value\n\t\t};\n\n\t\tthis._call('post', '\/' + app + '\/' + key, options);\n\t},\n\n\t\/**\n\t * @param {string} app\n\t * @param {string} key\n\t * @param {Object} [options]\n\t * @param {function} [options.success]\n\t * @param {function} [options.error]\n\t * @since 11.0.0\n\t *\/\n\tdeleteKey: function(app, key, options) {\n\t\tthis._call('delete', '\/' + app + '\/' + key, options);\n\t}\n};\n\n\n\/**\n * @copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>\n *\n * @author Arthur Schiwon <blizzz@arthur-schiwon.de>\n *\n * This file is licensed under the Affero General Public License version 3 or\n * later. See the COPYING file.\n *\/\n\n(function(OCP) {\n\t\"use strict\";\n\n\tOCP.Comments = {\n\n\t\t\/*\n\t\t * Detects links:\n\t\t * Either the http(s) protocol is given or two strings, basically limited to ascii with the last\n\t\t * \tword being at least one digit long,\n\t\t * followed by at least another character\n\t\t *\n\t\t * The downside: anything not ascii is excluded. Not sure how common it is in areas using different\n\t\t * alphabets\u2026 the upside: fake domains with similar looking characters won't be formatted as links\n\t\t *\/\n\t\turlRegex: \/(\\s|^)(https?:\\\/\\\/)?((?:[-A-Z0-9+_]+\\.)+[-A-Z]+(?:\\\/[-A-Z0-9+&@#%?=~_|!:,.;()]*)*)(\\s|$)\/ig,\n\n\t\tplainToRich: function(content) {\n\t\t\tcontent = this.formatLinksRich(content);\n\t\t\treturn content;\n\t\t},\n\n\t\trichToPlain: function(content) {\n\t\t\tcontent = this.formatLinksPlain(content);\n\t\t\treturn content;\n\t\t},\n\n\t\tformatLinksRich: function(content) {\n\t\t\treturn content.replace(this.urlRegex, function(_, leadingSpace, protocol, url, trailingSpace) {\n\t\t\t\tvar linkText = url;\n\t\t\t\tif(!protocol) {\n\t\t\t\t\tprotocol = 'https:\/\/';\n\t\t\t\t} else if (protocol === 'http:\/\/'){\n\t\t\t\t\tlinkText = protocol + url;\n\t\t\t\t}\n\n\t\t\t\treturn leadingSpace + '<a class=\"external\" target=\"_blank\" rel=\"noopener noreferrer\" href=\"' + protocol + url + '\">' + linkText + '<\/a>' + trailingSpace;\n\t\t\t});\n\t\t},\n\n\t\tformatLinksPlain: function(content) {\n\t\t\tvar $content = $('<div><\/div>').html(content);\n\t\t\t$content.find('a').each(function () {\n\t\t\t\tvar $this = $(this);\n\t\t\t\t$this.html($this.attr('href'));\n\t\t\t});\n\t\t\treturn $content.html();\n\t\t}\n\n\t};\n})(OCP);\n\n\n\/**\n * @copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>\n *\n * @author Arthur Schiwon <blizzz@arthur-schiwon.de>\n *\n * This file is licensed under the Affero General Public License version 3 or\n * later. See the COPYING file.\n *\/\n\n(function(OCP) {\n\t\"use strict\";\n\n\tOCP.WhatsNew = {\n\n\t\tquery: function(options) {\n\t\t\toptions = options || {};\n\t\t\tvar dismissOptions = options.dismiss || {};\n\t\t\t$.ajax({\n\t\t\t\ttype: 'GET',\n\t\t\t\turl: options.url || OC.linkToOCS('core', 2) + 'whatsnew?format=json',\n\t\t\t\tsuccess: options.success || function(data, statusText, xhr) {\n\t\t\t\t\tOCP.WhatsNew._onQuerySuccess(data, statusText, xhr, dismissOptions);\n\t\t\t\t},\n\t\t\t\terror: options.error || this._onQueryError\n\t\t\t});\n\t\t},\n\n\t\tdismiss: function(version, options) {\n\t\t\toptions = options || {};\n\t\t\t$.ajax({\n\t\t\t\ttype: 'POST',\n\t\t\t\turl: options.url || OC.linkToOCS('core', 2) + 'whatsnew',\n\t\t\t\tdata: {version: encodeURIComponent(version)},\n\t\t\t\tsuccess: options.success || this._onDismissSuccess,\n\t\t\t\terror: options.error || this._onDismissError\n\t\t\t});\n\t\t\t\/\/ remove element immediately\n\t\t\t$('.whatsNewPopover').remove();\n\t\t},\n\n\t\t_onQuerySuccess: function(data, statusText, xhr, dismissOptions) {\n\t\t\tconsole.debug('querying Whats New data was successful: ' + statusText);\n\t\t\tconsole.debug(data);\n\n\t\t\tif(xhr.status !== 200) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar item, menuItem, text, icon;\n\n\t\t\tvar div = document.createElement('div');\n\t\t\tdiv.classList.add('popovermenu', 'open', 'whatsNewPopover', 'menu-left');\n\n\t\t\tvar list = document.createElement('ul');\n\n\t\t\t\/\/ header\n\t\t\titem = document.createElement('li');\n\t\t\tmenuItem = document.createElement('span');\n\t\t\tmenuItem.className = \"menuitem\";\n\n\t\t\ttext = document.createElement('span');\n\t\t\ttext.innerText = t('core', 'New in') + ' ' + data['ocs']['data']['product'];\n\t\t\ttext.className = 'caption';\n\t\t\tmenuItem.appendChild(text);\n\n\t\t\ticon = document.createElement('span');\n\t\t\ticon.className = 'icon-close';\n\t\t\ticon.onclick = function () {\n\t\t\t\tOCP.WhatsNew.dismiss(data['ocs']['data']['version'], dismissOptions);\n\t\t\t};\n\t\t\tmenuItem.appendChild(icon);\n\n\t\t\titem.appendChild(menuItem);\n\t\t\tlist.appendChild(item);\n\n\t\t\t\/\/ Highlights\n\t\t\tfor (var i in data['ocs']['data']['whatsNew']['regular']) {\n\t\t\t\tvar whatsNewTextItem = data['ocs']['data']['whatsNew']['regular'][i];\n\t\t\t\titem = document.createElement('li');\n\n\t\t\t\tmenuItem = document.createElement('span');\n\t\t\t\tmenuItem.className = \"menuitem\";\n\n\t\t\t\ticon = document.createElement('span');\n\t\t\t\ticon.className = 'icon-checkmark';\n\t\t\t\tmenuItem.appendChild(icon);\n\n\t\t\t\ttext = document.createElement('p');\n\t\t\t\ttext.innerHTML = _.escape(whatsNewTextItem);\n\t\t\t\tmenuItem.appendChild(text);\n\n\t\t\t\titem.appendChild(menuItem);\n\t\t\t\tlist.appendChild(item);\n\t\t\t}\n\n\t\t\t\/\/ Changelog URL\n\t\t\tif(!_.isUndefined(data['ocs']['data']['changelogURL'])) {\n\t\t\t\titem = document.createElement('li');\n\n\t\t\t\tmenuItem = document.createElement('a');\n\t\t\t\tmenuItem.href = data['ocs']['data']['changelogURL'];\n\t\t\t\tmenuItem.rel = 'noreferrer noopener';\n\t\t\t\tmenuItem.target = '_blank';\n\n\t\t\t\ticon = document.createElement('span');\n\t\t\t\ticon.className = 'icon-link';\n\t\t\t\tmenuItem.appendChild(icon);\n\n\t\t\t\ttext = document.createElement('span');\n\t\t\t\ttext.innerText = t('core', 'View changelog');\n\t\t\t\tmenuItem.appendChild(text);\n\n\t\t\t\titem.appendChild(menuItem);\n\t\t\t\tlist.appendChild(item);\n\t\t\t}\n\n\t\t\tdiv.appendChild(list);\n\t\t\tdocument.body.appendChild(div);\n\t\t},\n\n\t\t_onQueryError: function (x, t, e) {\n\t\t\tconsole.debug('querying Whats New Data resulted in an error: ' + t + e);\n\t\t\tconsole.debug(x);\n\t\t},\n\n\t\t_onDismissSuccess: function(data) {\n\t\t\t\/\/noop\n\t\t},\n\n\t\t_onDismissError: function (data) {\n\t\t\tconsole.debug('dismissing Whats New data resulted in an error: ' + data);\n\t\t}\n\t};\n})(OCP);\n\n\n\/**\n * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com>\n *\n * @license GNU AGPL version 3 or any later version\n *\n * This program is free software: you can redistribute it and\/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program 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 this program.  If not, see <http:\/\/www.gnu.org\/licenses\/>.\n *\n *\/\n\n\/**\n * @namespace\n * @deprecated Use OCP.AppConfig instead\n *\/\nOC.AppConfig={\n\t\/**\n\t * @deprecated Use OCP.AppConfig.getValue() instead\n\t *\/\n\tgetValue:function(app,key,defaultValue,callback){\n\t\tOCP.AppConfig.getValue(app, key, defaultValue, {\n\t\t\tsuccess: callback\n\t\t});\n\t},\n\n\t\/**\n\t * @deprecated Use OCP.AppConfig.setValue() instead\n\t *\/\n\tsetValue:function(app,key,value){\n\t\tOCP.AppConfig.setValue(app, key, value);\n\t},\n\n\t\/**\n\t * @deprecated Use OCP.AppConfig.getApps() instead\n\t *\/\n\tgetApps:function(callback){\n\t\tOCP.AppConfig.getApps({\n\t\t\tsuccess: callback\n\t\t});\n\t},\n\n\t\/**\n\t * @deprecated Use OCP.AppConfig.getKeys() instead\n\t *\/\n\tgetKeys:function(app,callback){\n\t\tOCP.AppConfig.getKeys(app, {\n\t\t\tsuccess: callback\n\t\t});\n\t},\n\n\t\/**\n\t * @deprecated Use OCP.AppConfig.deleteKey() instead\n\t *\/\n\tdeleteKey:function(app,key){\n\t\tOCP.AppConfig.deleteKey(app, key);\n\t}\n};\n\n\n$(document).on('ajaxSend',function(elm, xhr, settings) {\n\tif(settings.crossDomain === false) {\n\t\txhr.setRequestHeader('requesttoken', oc_requesttoken);\n\t\txhr.setRequestHeader('OCS-APIREQUEST', 'true');\n\t}\n});\n\n\n\/**\n * ownCloud - core\n *\n * This file is licensed under the Affero General Public License version 3 or\n * later. See the COPYING file.\n *\n * @author Bernhard Posselt <dev@bernhard-posselt.com>\n * @copyright Bernhard Posselt 2014\n *\/\n\n(function (document, $, exports) {\n\n\t'use strict';\n\n\tvar dynamicSlideToggleEnabled = false;\n\n\texports.Apps = {\n\t\tenableDynamicSlideToggle: function () {\n\t\t\tdynamicSlideToggleEnabled = true;\n\t\t}\n\t};\n\n\t\/**\n\t * Shows the #app-sidebar and add .with-app-sidebar to subsequent siblings\n\t *\n\t * @param {Object} [$el] sidebar element to show, defaults to $('#app-sidebar')\n\t *\/\n\texports.Apps.showAppSidebar = function($el) {\n\t\tvar $appSidebar = $el || $('#app-sidebar');\n\t\t$appSidebar.removeClass('disappear')\n\t\t\t.show('slide', { direction: 'right' }, 300);\n\t\t$('#app-content').trigger(new $.Event('appresized'));\n\t};\n\n\t\/**\n\t * Shows the #app-sidebar and removes .with-app-sidebar from subsequent\n\t * siblings\n\t *\n\t * @param {Object} [$el] sidebar element to hide, defaults to $('#app-sidebar')\n\t *\/\n\texports.Apps.hideAppSidebar = function($el) {\n\t\tvar $appSidebar = $el || $('#app-sidebar');\n\t\t$appSidebar.hide('slide', { direction: 'right' }, 300,\n\t\t\tfunction() {\n\t\t\t\t$appSidebar.addClass('disappear');\n\t\t\t});\n\t\t$('#app-content').trigger(new $.Event('appresized'));\n\t};\n\n\t\/**\n\t * Provides a way to slide down a target area through a button and slide it\n\t * up if the user clicks somewhere else. Used for the news app settings and\n\t * add new field.\n\t *\n\t * Usage:\n\t * <button data-apps-slide-toggle=\".slide-area\">slide<\/button>\n\t * <div class=\".slide-area\" class=\"hidden\">I'm sliding up<\/div>\n\t *\/\n\tvar registerAppsSlideToggle = function () {\n\t\tvar buttons = $('[data-apps-slide-toggle]');\n\n\t\tif (buttons.length === 0) {\n\t\t\t$('#app-navigation').addClass('without-app-settings');\n\t\t}\n\n\t\t$(document).click(function (event) {\n\n\t\t\tif (dynamicSlideToggleEnabled) {\n\t\t\t\tbuttons = $('[data-apps-slide-toggle]');\n\t\t\t}\n\n\t\t\tbuttons.each(function (index, button) {\n\n\t\t\t\tvar areaSelector = $(button).data('apps-slide-toggle');\n\t\t\t\tvar area = $(areaSelector);\n\n\t\t\t\tfunction hideArea() {\n\t\t\t\t\tarea.slideUp(OC.menuSpeed*4, function() {\n\t\t\t\t\t\tarea.trigger(new $.Event('hide'));\n\t\t\t\t\t});\n\t\t\t\t\tarea.removeClass('opened');\n\t\t\t\t\t$(button).removeClass('opened');\n\t\t\t\t}\n\t\t\t\tfunction showArea() {\n\t\t\t\t\tarea.slideDown(OC.menuSpeed*4, function() {\n\t\t\t\t\t\tarea.trigger(new $.Event('show'));\n\t\t\t\t\t});\n\t\t\t\t\tarea.addClass('opened');\n\t\t\t\t\t$(button).addClass('opened');\n\t\t\t\t\tvar input = $(areaSelector + ' [autofocus]');\n\t\t\t\t\tif (input.length === 1) {\n\t\t\t\t\t\tinput.focus();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t\/\/ do nothing if the area is animated\n\t\t\t\tif (!area.is(':animated')) {\n\n\t\t\t\t\t\/\/ button toggles the area\n\t\t\t\t\tif ($(button).is($(event.target).closest('[data-apps-slide-toggle]'))) {\n\t\t\t\t\t\tif (area.is(':visible')) {\n\t\t\t\t\t\t\thideArea();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tshowArea();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\/\/ all other areas that have not been clicked but are open\n\t\t\t\t\t\/\/ should be slid up\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar closest = $(event.target).closest(areaSelector);\n\t\t\t\t\t\tif (area.is(':visible') && closest[0] !== area[0]) {\n\t\t\t\t\t\t\thideArea();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t});\n\t};\n\n\n\t$(document).ready(function () {\n\t\tregisterAppsSlideToggle();\n\t});\n\n}(document, jQuery, OC));\n\n\n\/**\n * @author Roeland Jago Douma <roeland@famdouma.nl>\n *\n * @copyright Copyright (c) 2015, ownCloud, Inc.\n * @license AGPL-3.0\n *\n * This code is free software: you can redistribute it and\/or modify\n * it under the terms of the GNU Affero General Public License, version 3,\n * as published by the Free Software Foundation.\n *\n * This program 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, version 3,\n * along with this program.  If not, see <http:\/\/www.gnu.org\/licenses\/>\n *\n *\/\n\n\/**\n * Namespace to hold functions related to convert mimetype to icons\n *\n * @namespace\n *\/\nOC.MimeType = {\n\n\t\/**\n\t * Cache that maps mimeTypes to icon urls\n\t *\/\n\t_mimeTypeIcons: {},\n\n\t\/**\n\t * Return the file icon we want to use for the given mimeType.\n\t * The file needs to be present in the supplied file list\n\t *\n\t * @param {string} mimeType The mimeType we want an icon for\n\t * @param {array} files The available icons in this theme\n\t * @return {string} The icon to use or null if there is no match\n\t *\/\n\t_getFile: function(mimeType, files) {\n\t\tvar icon = mimeType.replace(new RegExp('\/', 'g'), '-');\n\n\t\t\/\/ Generate path\n\t\tif (mimeType === 'dir' && $.inArray('folder', files) !== -1) {\n\t\t\treturn 'folder';\n\t\t} else if (mimeType === 'dir-encrypted' && $.inArray('folder-encrypted', files) !== -1) {\n\t\t\treturn 'folder-encrypted';\n\t\t} else if (mimeType === 'dir-shared' && $.inArray('folder-shared', files) !== -1) {\n\t\t\treturn 'folder-shared';\n\t\t} else if (mimeType === 'dir-public' && $.inArray('folder-public', files) !== -1) {\n\t\t\treturn 'folder-public';\n\t\t} else if (mimeType === 'dir-external' && $.inArray('folder-external', files) !== -1) {\n\t\t\treturn 'folder-external';\n\t\t} else if ($.inArray(icon, files) !== -1) {\n\t\t\treturn icon;\n\t\t} else if ($.inArray(icon.split('-')[0], files) !== -1) {\n\t\t\treturn icon.split('-')[0];\n\t\t} else if ($.inArray('file', files) !== -1) {\n\t\t\treturn 'file';\n\t\t}\n\n\t\treturn null;\n\t},\n\n\t\/**\n\t * Return the url to icon of the given mimeType\n\t *\n\t * @param {string} mimeType The mimeType to get the icon for\n\t * @return {string} Url to the icon for mimeType\n\t *\/\n\tgetIconUrl: function(mimeType) {\n\t\tif (_.isUndefined(mimeType)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\twhile (mimeType in OC.MimeTypeList.aliases) {\n\t\t\tmimeType = OC.MimeTypeList.aliases[mimeType];\n\t\t}\n\t\tif (mimeType in OC.MimeType._mimeTypeIcons) {\n\t\t\treturn OC.MimeType._mimeTypeIcons[mimeType];\n\t\t}\n\n\t\t\/\/ First try to get the correct icon from the current theme\n\t\tvar gotIcon = null;\n\t\tvar path = '';\n\t\tif (OC.theme.folder !== '' && $.isArray(OC.MimeTypeList.themes[OC.theme.folder])) {\n\t\t\tpath = OC.getRootPath() + '\/themes\/' + OC.theme.folder + '\/core\/img\/filetypes\/';\n\t\t\tvar icon = OC.MimeType._getFile(mimeType, OC.MimeTypeList.themes[OC.theme.folder]);\n\n\t\t\tif (icon !== null) {\n\t\t\t\tgotIcon = true;\n\t\t\t\tpath += icon;\n\t\t\t}\n\t\t}\n\t\tif(OCA.Theming && gotIcon === null) {\n\t\t\tpath = OC.generateUrl('\/apps\/theming\/img\/core\/filetypes\/');\n\t\t\tpath += OC.MimeType._getFile(mimeType, OC.MimeTypeList.files);\n\t\t\tgotIcon = true;\n\t\t}\n\n\t\t\/\/ If we do not yet have an icon fall back to the default\n\t\tif (gotIcon === null) {\n\t\t\tpath = OC.getRootPath() + '\/core\/img\/filetypes\/';\n\t\t\tpath += OC.MimeType._getFile(mimeType, OC.MimeTypeList.files);\n\t\t}\n\n\t\tpath += '.svg';\n\n\t\tif(OCA.Theming) {\n\t\t\tpath += \"?v=\" + OCA.Theming.cacheBuster;\n\t\t}\n\n\t\t\/\/ Cache the result\n\t\tOC.MimeType._mimeTypeIcons[mimeType] = path;\n\t\treturn path;\n\t}\n\n};\n\n\n\/**\n* This file is automatically generated\n* DO NOT EDIT MANUALLY!\n*\n* You can update the list of MimeType Aliases in config\/mimetypealiases.json\n* The list of files is fetched from core\/img\/filetypes\n* To regenerate this file run .\/occ maintenance:mimetype:update-js\n*\/\nOC.MimeTypeList={\n\taliases: {\n    \"application\/coreldraw\": \"image\",\n    \"application\/epub+zip\": \"text\",\n    \"application\/font-sfnt\": \"image\",\n    \"application\/font-woff\": \"image\",\n    \"application\/gpx+xml\": \"location\",\n    \"application\/illustrator\": \"image\",\n    \"application\/javascript\": \"text\/code\",\n    \"application\/json\": \"text\/code\",\n    \"application\/msaccess\": \"file\",\n    \"application\/msexcel\": \"x-office\/spreadsheet\",\n    \"application\/msonenote\": \"x-office\/document\",\n    \"application\/mspowerpoint\": \"x-office\/presentation\",\n    \"application\/msword\": \"x-office\/document\",\n    \"application\/octet-stream\": \"file\",\n    \"application\/postscript\": \"image\",\n    \"application\/rss+xml\": \"application\/xml\",\n    \"application\/vnd.android.package-archive\": \"package\/x-generic\",\n    \"application\/vnd.lotus-wordpro\": \"x-office\/document\",\n    \"application\/vnd.garmin.tcx+xml\": \"location\",\n    \"application\/vnd.google-earth.kml+xml\": \"location\",\n    \"application\/vnd.google-earth.kmz\": \"location\",\n    \"application\/vnd.ms-excel\": \"x-office\/spreadsheet\",\n    \"application\/vnd.ms-excel.addin.macroEnabled.12\": \"x-office\/spreadsheet\",\n    \"application\/vnd.ms-excel.sheet.binary.macroEnabled.12\": \"x-office\/spreadsheet\",\n    \"application\/vnd.ms-excel.sheet.macroEnabled.12\": \"x-office\/spreadsheet\",\n    \"application\/vnd.ms-excel.template.macroEnabled.12\": \"x-office\/spreadsheet\",\n    \"application\/vnd.ms-fontobject\": \"image\",\n    \"application\/vnd.ms-powerpoint\": \"x-office\/presentation\",\n    \"application\/vnd.ms-powerpoint.addin.macroEnabled.12\": \"x-office\/presentation\",\n    \"application\/vnd.ms-powerpoint.presentation.macroEnabled.12\": \"x-office\/presentation\",\n    \"application\/vnd.ms-powerpoint.slideshow.macroEnabled.12\": \"x-office\/presentation\",\n    \"application\/vnd.ms-powerpoint.template.macroEnabled.12\": \"x-office\/presentation\",\n    \"application\/vnd.ms-visio.drawing.macroEnabled.12\": \"application\/vnd.visio\",\n    \"application\/vnd.ms-visio.drawing\": \"application\/vnd.visio\",\n    \"application\/vnd.ms-visio.stencil.macroEnabled.12\": \"application\/vnd.visio\",\n    \"application\/vnd.ms-visio.stencil\": \"application\/vnd.visio\",\n    \"application\/vnd.ms-visio.template.macroEnabled.12\": \"application\/vnd.visio\",\n    \"application\/vnd.ms-visio.template\": \"application\/vnd.visio\",\n    \"application\/vnd.ms-word.document.macroEnabled.12\": \"x-office\/document\",\n    \"application\/vnd.ms-word.template.macroEnabled.12\": \"x-office\/document\",\n    \"application\/vnd.oasis.opendocument.presentation\": \"x-office\/presentation\",\n    \"application\/vnd.oasis.opendocument.presentation-template\": \"x-office\/presentation\",\n    \"application\/vnd.oasis.opendocument.spreadsheet\": \"x-office\/spreadsheet\",\n    \"application\/vnd.oasis.opendocument.spreadsheet-template\": \"x-office\/spreadsheet\",\n    \"application\/vnd.oasis.opendocument.text\": \"x-office\/document\",\n    \"application\/vnd.oasis.opendocument.text-master\": \"x-office\/document\",\n    \"application\/vnd.oasis.opendocument.text-template\": \"x-office\/document\",\n    \"application\/vnd.oasis.opendocument.text-web\": \"x-office\/document\",\n    \"application\/vnd.openxmlformats-officedocument.presentationml.presentation\": \"x-office\/presentation\",\n    \"application\/vnd.openxmlformats-officedocument.presentationml.slideshow\": \"x-office\/presentation\",\n    \"application\/vnd.openxmlformats-officedocument.presentationml.template\": \"x-office\/presentation\",\n    \"application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet\": \"x-office\/spreadsheet\",\n    \"application\/vnd.openxmlformats-officedocument.spreadsheetml.template\": \"x-office\/spreadsheet\",\n    \"application\/vnd.openxmlformats-officedocument.wordprocessingml.document\": \"x-office\/document\",\n    \"application\/vnd.openxmlformats-officedocument.wordprocessingml.template\": \"x-office\/document\",\n    \"application\/vnd.visio\": \"x-office\/document\",\n    \"application\/vnd.wordperfect\": \"x-office\/document\",\n    \"application\/x-7z-compressed\": \"package\/x-generic\",\n    \"application\/x-bzip2\": \"package\/x-generic\",\n    \"application\/x-cbr\": \"text\",\n    \"application\/x-compressed\": \"package\/x-generic\",\n    \"application\/x-dcraw\": \"image\",\n    \"application\/x-deb\": \"package\/x-generic\",\n    \"application\/x-fictionbook+xml\": \"text\",\n    \"application\/x-font\": \"image\",\n    \"application\/x-gimp\": \"image\",\n    \"application\/x-gzip\": \"package\/x-generic\",\n    \"application\/x-iwork-keynote-sffkey\": \"x-office\/presentation\",\n    \"application\/x-iwork-numbers-sffnumbers\": \"x-office\/spreadsheet\",\n    \"application\/x-iwork-pages-sffpages\": \"x-office\/document\",\n    \"application\/x-mobipocket-ebook\": \"text\",\n    \"application\/x-perl\": \"text\/code\",\n    \"application\/x-photoshop\": \"image\",\n    \"application\/x-php\": \"text\/code\",\n    \"application\/x-rar-compressed\": \"package\/x-generic\",\n    \"application\/x-tar\": \"package\/x-generic\",\n    \"application\/x-tex\": \"text\",\n    \"application\/xml\": \"text\/html\",\n    \"application\/yaml\": \"text\/code\",\n    \"application\/zip\": \"package\/x-generic\",\n    \"database\": \"file\",\n    \"httpd\/unix-directory\": \"dir\",\n    \"text\/css\": \"text\/code\",\n    \"text\/csv\": \"x-office\/spreadsheet\",\n    \"text\/html\": \"text\/code\",\n    \"text\/x-c\": \"text\/code\",\n    \"text\/x-c++src\": \"text\/code\",\n    \"text\/x-h\": \"text\/code\",\n    \"text\/x-java-source\": \"text\/code\",\n    \"text\/x-ldif\": \"text\/code\",\n    \"text\/x-python\": \"text\/code\",\n    \"text\/x-shellscript\": \"text\/code\",\n    \"web\": \"text\/code\",\n    \"application\/internet-shortcut\": \"link\"\n},\n\tfiles: [\n    \"application\",\n    \"application-pdf\",\n    \"audio\",\n    \"file\",\n    \"folder\",\n    \"folder-drag-accept\",\n    \"folder-encrypted\",\n    \"folder-external\",\n    \"folder-public\",\n    \"folder-shared\",\n    \"folder-starred\",\n    \"image\",\n    \"link\",\n    \"location\",\n    \"package-x-generic\",\n    \"text\",\n    \"text-calendar\",\n    \"text-code\",\n    \"text-vcard\",\n    \"video\",\n    \"x-office-document\",\n    \"x-office-presentation\",\n    \"x-office-spreadsheet\"\n],\n\tthemes: []\n};\n\n\n\/*\n * Copyright (c) 2015\n *\n * This file is licensed under the Affero General Public License version 3\n * or later.\n *\n * See the COPYING-README file.\n *\n *\/\n\n\/* global Backbone *\/\nif(!_.isUndefined(Backbone)) {\n\tOC.Backbone = Backbone.noConflict();\n}\n\n\n\/*\n * Copyright (c) 2015\n *\n * This file is licensed under the Affero General Public License version 3\n * or later.\n *\n * See the COPYING-README file.\n *\n *\/\n\n\/* global Select2 *\/\n\n\/**\n * Select2 extension for toggling values in a multi-select dropdown\n *\/\n(function(Select2) {\n\n\tvar Select2FindHighlightableChoices = Select2.class.multi.prototype.findHighlightableChoices;\n\tSelect2.class.multi.prototype.findHighlightableChoices = function () {\n\t\tif (this.opts.toggleSelect) {\n\t\t\treturn this.results.find('.select2-result-selectable:not(.select2-disabled)');\n\t\t}\n\t\treturn Select2FindHighlightableChoices.apply(this, arguments);\n\t};\n\n\tvar Select2TriggerSelect = Select2.class.multi.prototype.triggerSelect;\n\tSelect2.class.multi.prototype.triggerSelect = function (data) {\n\t\tif (this.opts.toggleSelect && this.val().indexOf(this.id(data)) !== -1) {\n\t\t\tvar self = this;\n\t\t\tvar val = this.id(data);\n\n\t\t\tvar selectionEls = this.container.find('.select2-search-choice').filter(function() {\n\t\t\t\treturn (self.id($(this).data('select2-data')) === val);\n\t\t\t});\n\n\t\t\tif (this.unselect(selectionEls)) {\n\t\t\t\t\/\/ also unselect in dropdown\n\t\t\t\tthis.results.find('.select2-result.select2-selected').each(function () {\n\t\t\t\t\tvar $this = $(this);\n\t\t\t\t\tif (self.id($this.data('select2-data')) === val) {\n\t\t\t\t\t\t$this.removeClass('select2-selected');\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tthis.clearSearch();\n\t\t\t}\n\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn Select2TriggerSelect.apply(this, arguments);\n\t\t}\n\t};\n\n})(Select2);\n\n\n\n\/**\n * ownCloud\n *\n * @author John Molakvo\u00e6\n * @copyright 2016-2018 John Molakvo\u00e6 <skjnldsv@protonmail.com>\n * @author Morris Jobke\n * @copyright 2013 Morris Jobke <morris.jobke@gmail.com>\n *\n * This library is free software; you can redistribute it and\/or\n * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library 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\n * License along with this library.  If not, see <http:\/\/www.gnu.org\/licenses\/>.\n *\n *\/\n\n\/*\n * Adds a background color to the element called on and adds the first character\n * of the passed in string. This string is also the seed for the generation of\n * the background color.\n *\n * You have following HTML:\n *\n * <div id=\"albumart\"><\/div>\n *\n * And call this from Javascript:\n *\n * $('#albumart').imageplaceholder('The Album Title');\n *\n * Which will result in:\n *\n * <div id=\"albumart\" style=\"background-color: rgb(121, 90, 171); ... \">T<\/div>\n *\n * You may also call it like this, to have a different background, than the seed:\n *\n * $('#albumart').imageplaceholder('The Album Title', 'Album Title');\n *\n * Resulting in:\n *\n * <div id=\"albumart\" style=\"background-color: rgb(121, 90, 171); ... \">A<\/div>\n *\n *\/\n\n \/*\n * Alternatively, you can use the prototype function to convert your string to rgb colors:\n *\n * \"a6741a86aded5611a8e46ce16f2ad646\".toRgb()\n *\n * Will return the rgb parameters within the following object:\n *\n * Color\u00a0{r: 208, g: 158, b: 109}\n *\n *\/\n\n(function ($) {\n\n\tString.prototype.toRgb = function() {\n\t\t\/\/ Normalize hash\t\t\n\t\tvar hash = this.toLowerCase();\n\n\t\t\/\/ Already a md5 hash?\n\t\tif( hash.match(\/^([0-9a-f]{4}-?){8}$\/) === null ) {\n\t\t\thash = md5(hash);\n\t\t}\n\n\t\thash = hash.replace(\/[^0-9a-f]\/g, '');\n\n\t\tfunction Color(r,g,b) {\n\t\t\tthis.r = r;\n\t\t\tthis.g = g;\n\t\t\tthis.b = b;\n\t\t}\n\n\t\tfunction stepCalc(steps, ends) {\n\t\t\tvar step = new Array(3);\n\t\t\tstep[0] = (ends[1].r - ends[0].r) \/ steps;\n\t\t\tstep[1] = (ends[1].g - ends[0].g) \/ steps;\n\t\t\tstep[2] = (ends[1].b - ends[0].b) \/ steps;\n\t\t\treturn step;\n\t\t}\n\n\t\tfunction mixPalette(steps, color1, color2) {\n\t\t\tvar count = steps + 1;\n\t\t\tvar palette = new Array();\n\t\t\tpalette.push(color1);\n\t\t\tvar step = stepCalc(steps, [color1, color2])\n\t\t\tfor (var i = 1; i < steps; i++) {\n\t\t\t\tvar r = parseInt(color1.r + (step[0] * i));\n\t\t\t\tvar g = parseInt(color1.g + (step[1] * i));\n\t\t\t\tvar b = parseInt(color1.b + (step[2] * i));\n\t\t\t\t\tpalette.push(new Color(r,g,b));\n\t\t\t}\n\t\t\treturn palette;\n\t\t}\n\n\t\tvar red = new Color(182, 70, 157);\n\t\tvar yellow = new Color(221, 203, 85);\n\t\tvar blue = new Color(0, 130, 201); \/\/ Nextcloud blue\n\t\t\/\/ Number of steps to go from a color to another\n\t\t\/\/ 3 colors * 6 will result in 18 generated colors\n\t\tvar steps = 6;\n\n\t\tvar palette1 = mixPalette(steps, red, yellow);\n\t\tvar palette2 = mixPalette(steps, yellow, blue);\n\t\tvar palette3 = mixPalette(steps, blue, red);\n\n\t\tvar finalPalette = palette1.concat(palette2).concat(palette3);\n\n\t\t\/\/ Convert a string to an integer evenly\n\t\tfunction hashToInt(hash, maximum) {\n\t\t\tvar finalInt = 0;\n\t\t\tvar result = Array();\n\n\t\t\t\/\/ Splitting evenly the string\n\t\t\tfor (var i=0; i<hash.length; i++) {\n\t\t\t\t\/\/ chars in md5 goes up to f, hex:16\n\t\t\t\tresult.push(parseInt(hash.charAt(i), 16) % 16);\n\t\t\t}\n\t\t\t\/\/ Adds up all results\n\t\t\tfor (var j in result) {\n\t\t\t\tfinalInt += result[j];\n\t\t\t}\n\t\t\t\/\/ chars in md5 goes up to f, hex:16\n\t\t\t\/\/ make sure we're always using int in our operation\n\t\t\treturn parseInt(parseInt(finalInt) % maximum);\n\t\t}\n\t\treturn finalPalette[hashToInt(hash, steps * 3 )];\n\t};\n\n\t$.fn.imageplaceholder = function(seed, text, size) {\n\t\ttext = text || seed;\n\n\t\t\/\/ Compute the hash\n\t\tvar rgb = seed.toRgb();\n\t\tthis.css('background-color', 'rgb('+rgb.r+', '+rgb.g+', '+rgb.b+')');\n\n\t\t\/\/ Placeholders are square\n\t\tvar height = this.height() || size || 32;\n\t\tthis.height(height);\n\t\tthis.width(height);\n\n\t\t\/\/ CSS rules\n\t\tthis.css('color', '#fff');\n\t\tthis.css('font-weight', 'normal');\n\t\tthis.css('text-align', 'center');\n\n\t\t\/\/ calculate the height\n\t\tthis.css('line-height', height + 'px');\n\t\tthis.css('font-size', (height * 0.55) + 'px');\n\n\t\tif(seed !== null && seed.length) {\n\t\t\tthis.html(text[0].toUpperCase());\n\t\t}\n\t};\n\n\t$.fn.clearimageplaceholder = function() {\n\t\tthis.css('background-color', '');\n\t\tthis.css('color', '');\n\t\tthis.css('font-weight', '');\n\t\tthis.css('text-align', '');\n\t\tthis.css('line-height', '');\n\t\tthis.css('font-size', '');\n\t\tthis.html('');\n\t\tthis.removeClass('icon-loading');\n\t\tthis.removeClass('icon-loading-small');\n\t};\n}(jQuery));\n\n\n\/**\n * Copyright (c) 2013 Christopher Sch\u00e4pers <christopher@schaepers.it>\n * This file is licensed under the Affero General Public License version 3 or\n * later.\n * See the COPYING-README file.\n *\/\n\n\/**\n * This plugin inserts the right avatar for the user, depending on, whether a\n * custom avatar is uploaded - which it uses then - or not, and display a\n * placeholder with the first letter of the users name instead.\n * For this it queries the core_avatar_get route, thus this plugin is fit very\n * tightly for owncloud, and it may not work anywhere else.\n *\n * You may use this on any <div><\/div>\n * Here I'm using <div class=\"avatardiv\"><\/div> as an example.\n *\n * There are 5 ways to call this:\n *\n * 1. $('.avatardiv').avatar('jdoe', 128);\n * This will make the div to jdoe's fitting avatar, with a size of 128px.\n *\n * 2. $('.avatardiv').avatar('jdoe');\n * This will make the div to jdoe's fitting avatar. If the div already has a\n * height, it will be used for the avatars size. Otherwise this plugin will\n * search for 'size' DOM data, to use for avatar size. If neither are available\n * it will default to 64px.\n *\n * 3. $('.avatardiv').avatar();\n * This will search the DOM for 'user' data, to use as the username. If there\n * is no username available it will default to a placeholder with the value of\n * \"?\". The size will be determined the same way, as the second example.\n *\n * 4. $('.avatardiv').avatar('jdoe', 128, true);\n * This will behave like the first example, except it will also append random\n * hashes to the custom avatar images, to force image reloading in IE8.\n *\n * 5. $('.avatardiv').avatar('jdoe', 128, undefined, true);\n * This will behave like the first example, but it will hide the avatardiv, if\n * it will display the default placeholder. undefined is the ie8fix from\n * example 4 and can be either true, or false\/undefined, to be ignored.\n *\n * 6. $('.avatardiv').avatar('jdoe', 128, undefined, true, callback);\n * This will behave like the above example, but it will call the function\n * defined in callback after the avatar is placed into the DOM.\n *\n *\/\n\n(function ($) {\n\t$.fn.avatar = function(user, size, ie8fix, hidedefault, callback, displayname) {\n\t\tvar setAvatarForUnknownUser = function(target) {\n\t\t\ttarget.imageplaceholder('?');\n\t\t\ttarget.css('background-color', '#b9b9b9');\n\t\t};\n\n\t\tif (typeof(user) !== 'undefined') {\n\t\t\tuser = String(user);\n\t\t}\n\t\tif (typeof(displayname) !== 'undefined') {\n\t\t\tdisplayname = String(displayname);\n\t\t}\n\n\t\tif (typeof(size) === 'undefined') {\n\t\t\tif (this.height() > 0) {\n\t\t\t\tsize = this.height();\n\t\t\t} else if (this.data('size') > 0) {\n\t\t\t\tsize = this.data('size');\n\t\t\t} else {\n\t\t\t\tsize = 64;\n\t\t\t}\n\t\t}\n\n\t\tthis.height(size);\n\t\tthis.width(size);\n\n\t\tif (typeof(user) === 'undefined') {\n\t\t\tif (typeof(this.data('user')) !== 'undefined') {\n\t\t\t\tuser = this.data('user');\n\t\t\t} else {\n\t\t\t\tsetAvatarForUnknownUser(this);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t\/\/ sanitize\n\t\tuser = String(user).replace(\/\\\/\/g,'');\n\n\t\tvar $div = this;\n\t\tvar url;\n\n\t\t\/\/ If this is our own avatar we have to use the version attribute\n\t\tif (user === OC.getCurrentUser().uid) {\n\t\t\turl = OC.generateUrl(\n\t\t\t\t'\/avatar\/{user}\/{size}?v={version}',\n\t\t\t\t{\n\t\t\t\t\tuser: user,\n\t\t\t\t\tsize: Math.ceil(size * window.devicePixelRatio),\n\t\t\t\t\tversion: oc_userconfig.avatar.version\n\t\t\t\t});\n\t\t} else {\n\t\t\turl = OC.generateUrl(\n\t\t\t\t'\/avatar\/{user}\/{size}',\n\t\t\t\t{\n\t\t\t\t\tuser: user,\n\t\t\t\t\tsize: Math.ceil(size * window.devicePixelRatio)\n\t\t\t\t});\n\t\t}\n\n\t\tvar img = new Image();\n\n\t\t\/\/ If the new image loads successfully set it.\n\t\timg.onload = function() {\n\t\t\t$div.clearimageplaceholder();\n\t\t\t$div.append(img);\n\n\t\t\tif(typeof callback === 'function') {\n\t\t\t\tcallback();\n\t\t\t}\n\t\t};\n\t\t\/\/ Fallback when avatar loading fails:\n\t\t\/\/ Use old placeholder when a displayname attribute is defined,\n\t\t\/\/ otherwise show the unknown user placeholder.\n\t\timg.onerror = function () {\n\t\t\t$div.clearimageplaceholder();\n\t\t\tif (typeof(displayname) !== 'undefined') {\n\t\t\t\t$div.imageplaceholder(user, displayname);\n\t\t\t} else {\n\t\t\t\tsetAvatarForUnknownUser($div);\n\t\t\t}\n\n\t\t\tif(typeof callback === 'function') {\n\t\t\t\tcallback();\n\t\t\t}\n\t\t};\n\n\t\tif (size < 32) {\n\t\t\t$div.addClass('icon-loading-small');\n\t\t} else {\n\t\t\t$div.addClass('icon-loading');\n\t\t}\n\t\timg.width = size;\n\t\timg.height = size;\n\t\timg.src = url;\n\t\timg.alt = '';\n\t};\n}(jQuery));\n\n\n\/**\n * Copyright (c) 2017 Georg Ehrke <oc.list@georgehrke.com>\n * This file is licensed under the Affero General Public License version 3 or\n * later.\n * See the COPYING-README file.\n *\/\n\n(function ($) {\n\n\tvar LIST = ''\n\t\t+ '<div class=\"menu popovermenu menu-left hidden contactsmenu-popover\">'\n\t\t+ '    <ul>'\n\t\t+ '        <li>'\n\t\t+ '            <a>'\n\t\t+ '                <span class=\"icon-loading-small\"><\/span>'\n\t\t+ '            <\/a>'\n\t\t+ '        <\/li>'\n\t\t+ '    <\/ul>'\n\t\t+ '<\/div>';\n\n\t$.fn.contactsMenu = function(shareWith, shareType, appendTo) {\n\t\t\/\/ 0 - user, 4 - email, 6 - remote\n\t\tvar allowedTypes = [0, 4, 6];\n\t\tif (allowedTypes.indexOf(shareType) === -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar $div = this;\n\t\tappendTo.append(LIST);\n\t\tvar $list = appendTo.find('div.contactsmenu-popover');\n\n\t\t$div.click(function() {\n\t\t\tif (!$list.hasClass('hidden')) {\n\t\t\t\t$list.addClass('hidden');\n\t\t\t\t$list.hide();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t$list.removeClass('hidden');\n\t\t\t$list.show();\n\n\t\t\tif ($list.hasClass('loaded')) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t$list.addClass('loaded');\n\t\t\t$.ajax(OC.generateUrl('\/contactsmenu\/findOne'), {\n\t\t\t\tmethod: 'POST',\n\t\t\t\tdata: {\n\t\t\t\t\tshareType: shareType,\n\t\t\t\t\tshareWith: shareWith\n\t\t\t\t}\n\t\t\t}).then(function(data) {\n\t\t\t\t$list.find('ul').find('li').addClass('hidden');\n\n\t\t\t\tvar actions;\n\t\t\t\tif (!data.topAction) {\n\t\t\t\t\tactions = [{\n\t\t\t\t\t\thyperlink: '#',\n\t\t\t\t\t\ttitle: t('core', 'No action available')\n\t\t\t\t\t}];\n\t\t\t\t} else {\n\t\t\t\t\tactions = [data.topAction].concat(data.actions);\n\t\t\t\t}\n\n\t\t\t\tactions.forEach(function(action) {\n\t\t\t\t\tvar template = OC.ContactsMenu.Templates['jquery_entry'];\n\t\t\t\t\t$list.find('ul').append(template(action));\n\t\t\t\t});\n\n\t\t\t\tif (actions.length === 0) {\n\n\t\t\t\t}\n\t\t\t}, function(jqXHR) {\n\t\t\t\t$list.find('ul').find('li').addClass('hidden');\n\n\t\t\t\tvar title;\n\t\t\t\tif (jqXHR.status === 404) {\n\t\t\t\t\ttitle = t('core', 'No action available');\n\t\t\t\t} else {\n\t\t\t\t\ttitle = t('core', 'Error fetching contact actions');\n\t\t\t\t}\n\n\t\t\t\tvar template = OC.ContactsMenu.Templates['jquery_entry'];\n\t\t\t\t$list.find('ul').append(template({\n\t\t\t\t\thyperlink: '#',\n\t\t\t\t\ttitle: title\n\t\t\t\t}));\n\t\t\t});\n\t\t});\n\n\t\t$(document).click(function(event) {\n\t\t\tvar clickedList = ($list.has(event.target).length > 0);\n\t\t\tvar clickedTarget = ($div.has(event.target).length > 0);\n\n\t\t\t$div.each(function() {\n\t\t\t\tif ($(this).is(event.target)) {\n\t\t\t\t\tclickedTarget = true;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (clickedList || clickedTarget) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t$list.addClass('hidden');\n\t\t\t$list.hide();\n\t\t});\n\t};\n}(jQuery));\n\n\n"]},{"file":"\/var\/www\/nextcloud\/lib\/private\/Template\/JSCombiner.php","line":103,"function":"cache","class":"OC\\Template\\JSCombiner","type":"->","args":["\/var\/www\/nextcloud\/core\/js","merged-template-prepend.js",{"__class__":"OC\\Files\\SimpleFS\\SimpleFolder"}]},{"file":"\/var\/www\/nextcloud\/lib\/private\/Template\/JSResourceLocator.php","line":114,"function":"process","class":"OC\\Template\\JSCombiner","type":"->","args":["\/var\/www\/nextcloud","core\/js\/merged-template-prepend.json","core"]},{"file":"\/var\/www\/nextcloud\/lib\/private\/Template\/JSResourceLocator.php","line":70,"function":"cacheAndAppendCombineJsonIfExist","class":"OC\\Template\\JSResourceLocator","type":"->","args":["\/var\/www\/nextcloud","core\/js\/merged-template-prepend.json"]},{"file":"\/var\/www\/nextcloud\/lib\/private\/Template\/ResourceLocator.php","line":78,"function":"doFind","class":"OC\\Template\\JSResourceLocator","type":"->","args":["js\/merged-template-prepend"]},{"file":"\/var\/www\/nextcloud\/lib\/private\/TemplateLayout.php","line":322,"function":"find","class":"OC\\Template\\ResourceLocator","type":"->","args":[["vendor\/core","js\/merged-template-prepend","search\/js\/search","core\/l10n\/de","core\/js\/merged-share-backend","firstrunwizard\/l10n\/de","firstrunwizard\/js\/jquery.colorbox","firstrunwizard\/js\/firstrunwizard","files_pdfviewer\/l10n\/en","files_pdfviewer\/js\/previewplugin","files_videoplayer\/l10n\/en","files_videoplayer\/js\/viewer","gallery\/l10n\/de","search\/l10n\/de","search\/js\/searchprovider","js\/jquery-ui-fixes","js\/files\/fileinfo","js\/files\/client","js\/contactsmenu","js\/contactsmenu_templates","vendor\/jsTimezoneDetect\/jstz","core\/js\/merged-login"]]},{"file":"\/var\/www\/nextcloud\/lib\/private\/TemplateLayout.php","line":154,"function":"findJavascriptFiles","class":"OC\\TemplateLayout","type":"::","args":[["vendor\/core","js\/merged-template-prepend","search\/js\/search","core\/l10n\/de","core\/js\/merged-share-backend","firstrunwizard\/l10n\/de","firstrunwizard\/js\/jquery.colorbox","firstrunwizard\/js\/firstrunwizard","files_pdfviewer\/l10n\/en","files_pdfviewer\/js\/previewplugin","files_videoplayer\/l10n\/en","files_videoplayer\/js\/viewer","gallery\/l10n\/de","search\/l10n\/de","search\/js\/searchprovider","js\/jquery-ui-fixes","js\/files\/fileinfo","js\/files\/client","js\/contactsmenu","js\/contactsmenu_templates","vendor\/jsTimezoneDetect\/jstz","core\/js\/merged-login"]]},{"file":"\/var\/www\/nextcloud\/lib\/private\/legacy\/template.php","line":211,"function":"__construct","class":"OC\\TemplateLayout","type":"->","args":["error",""]},{"file":"\/var\/www\/nextcloud\/lib\/private\/Template\/Base.php","line":132,"function":"fetchPage","class":"OC_Template","type":"->","args":[]},{"file":"\/var\/www\/nextcloud\/lib\/private\/legacy\/template.php","line":360,"function":"printPage","class":"OC\\Template\\Base","type":"->","args":[]},{"file":"\/var\/www\/nextcloud\/index.php","line":69,"function":"printExceptionErrorPage","class":"OC_Template","type":"::","args":[{"__class__":"OCP\\Files\\NotFoundException"},500]}],"File":"\/var\/www\/nextcloud\/lib\/private\/Files\/Node\/Node.php","Line":97,"CustomMessage":"--"},"userAgent":"Mozilla\/5.0 (Windows NT 6.1; Win64; x64; rv:65.0) Gecko\/20100101 Firefox\/65.0","version":"15.0.4.0"}
  21. root@bananapim2:/var/www/nextcloud/data#
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement