| /*! | 
|  * bootstrap-fileinput v4.3.6 | 
|  * http://plugins.krajee.com/file-input | 
|  * | 
|  * Author: Kartik Visweswaran | 
|  * Copyright: 2014 - 2016, Kartik Visweswaran, Krajee.com | 
|  * | 
|  * Licensed under the BSD 3-Clause | 
|  * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md | 
|  */ | 
| (function (factory) { | 
|     "use strict"; | 
|     //noinspection JSUnresolvedVariable | 
|     if (typeof define === 'function' && define.amd) { // jshint ignore:line | 
|         // AMD. Register as an anonymous module. | 
|         define(['jquery'], factory); // jshint ignore:line | 
|     } else { // noinspection JSUnresolvedVariable | 
|         if (typeof module === 'object' && module.exports) { // jshint ignore:line | 
|             // Node/CommonJS | 
|             // noinspection JSUnresolvedVariable | 
|             module.exports = factory(require('jquery')); // jshint ignore:line | 
|         } else { | 
|             // Browser globals | 
|             factory(window.jQuery); | 
|         } | 
|     } | 
| }(function ($) { | 
|     "use strict"; | 
|   | 
|     $.fn.fileinputLocales = {}; | 
|     $.fn.fileinputThemes = {}; | 
|   | 
|     var NAMESPACE, MODAL_ID, STYLE_SETTING, OBJECT_PARAMS, DEFAULT_PREVIEW, objUrl, compare, isIE, handler, | 
|         previewCache, getNum, hasFileAPISupport, hasDragDropSupport, hasFileUploadSupport, addCss, tMain1, tMain2, | 
|         tPreview, tFileIcon, tClose, tCaption, tBtnDefault, tBtnLink, tBtnBrowse, tModalMain, tModal, tProgress, tSize, | 
|         tFooter, tActions, tActionDelete, tActionUpload, tActionZoom, tActionDrag, tTagBef, tTagBef1, tTagBef2, tTagAft, | 
|         tGeneric, tHtml, tImage, tText, tVideo, tAudio, tFlash, tObject, tPdf, tOther, defaultFileActionSettings, | 
|         defaultLayoutTemplates, defaultPreviewTemplates, defaultPreviewZoomSettings, defaultPreviewTypes, getElement, | 
|         defaultPreviewSettings, defaultFileTypeSettings, isEmpty, isArray, ifSet, uniqId, htmlEncode, replaceTags, | 
|         cleanMemory, findFileName, checkFullScreen, toggleFullScreen, moveArray, FileInput; | 
|   | 
|     NAMESPACE = '.fileinput'; | 
|     MODAL_ID = 'kvFileinputModal'; | 
|     STYLE_SETTING = 'style="width:{width};height:{height};"'; | 
|     OBJECT_PARAMS = '<param name="controller" value="true" />\n' + | 
|         '<param name="allowFullScreen" value="true" />\n' + | 
|         '<param name="allowScriptAccess" value="always" />\n' + | 
|         '<param name="autoPlay" value="false" />\n' + | 
|         '<param name="autoStart" value="false" />\n' + | 
|         '<param name="quality" value="high" />\n'; | 
|     DEFAULT_PREVIEW = '<div class="file-preview-other">\n' + | 
|         '<span class="{previewFileIconClass}">{previewFileIcon}</span>\n' + | 
|         '</div>'; | 
|     //noinspection JSUnresolvedVariable | 
|     objUrl = window.URL || window.webkitURL; | 
|     compare = function (input, str, exact) { | 
|         return input !== undefined && (exact ? input === str : input.match(str)); | 
|     }; | 
|     isIE = function (ver) { | 
|         // check for IE versions < 11 | 
|         if (navigator.appName !== 'Microsoft Internet Explorer') { | 
|             return false; | 
|         } | 
|         if (ver === 10) { | 
|             return new RegExp('msie\\s' + ver, 'i').test(navigator.userAgent); | 
|         } | 
|         var div = document.createElement("div"), status; | 
|         div.innerHTML = "<!--[if IE " + ver + "]> <i></i> <![endif]-->"; | 
|         status = div.getElementsByTagName("i").length; | 
|         document.body.appendChild(div); | 
|         div.parentNode.removeChild(div); | 
|         return status; | 
|     }; | 
|     handler = function ($el, event, callback, skipNS) { | 
|         var ev = skipNS ? event : event.split(' ').join(NAMESPACE + ' ') + NAMESPACE; | 
|         $el.off(ev).on(ev, callback); | 
|     }; | 
|     previewCache = { | 
|         data: {}, | 
|         init: function (obj) { | 
|             var content = obj.initialPreview, id = obj.id; | 
|             if (content.length > 0 && !isArray(content)) { | 
|                 content = content.split(obj.initialPreviewDelimiter); | 
|             } | 
|             previewCache.data[id] = { | 
|                 content: content, | 
|                 config: obj.initialPreviewConfig, | 
|                 tags: obj.initialPreviewThumbTags, | 
|                 delimiter: obj.initialPreviewDelimiter, | 
|                 previewFileType: obj.initialPreviewFileType, | 
|                 previewAsData: obj.initialPreviewAsData, | 
|                 template: obj.previewGenericTemplate, | 
|                 showZoom: obj.fileActionSettings.showZoom, | 
|                 showDrag: obj.fileActionSettings.showDrag, | 
|                 getSize: function (size) { | 
|                     return obj._getSize(size); | 
|                 }, | 
|                 parseTemplate: function (cat, data, fname, ftype, pId, ftr, ind) { | 
|                     var fc = ' file-preview-initial'; | 
|                     return obj._generatePreviewTemplate(cat, data, fname, ftype, pId, false, null, fc, ftr, ind); | 
|                 }, | 
|                 msg: function (n) { | 
|                     return obj._getMsgSelected(n); | 
|                 }, | 
|                 initId: obj.previewInitId, | 
|                 footer: obj._getLayoutTemplate('footer').replace(/\{progress}/g, obj._renderThumbProgress()), | 
|                 isDelete: obj.initialPreviewShowDelete, | 
|                 caption: obj.initialCaption, | 
|                 actions: function (showUpload, showDelete, showZoom, showDrag, disabled, url, key) { | 
|                     return obj._renderFileActions(showUpload, showDelete, showZoom, showDrag, disabled, url, key, true); | 
|                 } | 
|             }; | 
|         }, | 
|         fetch: function (id) { | 
|             return previewCache.data[id].content.filter(function (n) { | 
|                 return n !== null; | 
|             }); | 
|         }, | 
|         count: function (id, all) { | 
|             return !!previewCache.data[id] && !!previewCache.data[id].content ? | 
|                 (all ? previewCache.data[id].content.length : previewCache.fetch(id).length) : 0; | 
|         }, | 
|         get: function (id, i, isDisabled) { | 
|             var ind = 'init_' + i, data = previewCache.data[id], config = data.config[i], content = data.content[i], | 
|                 previewId = data.initId + '-' + ind, out, $tmp, frameClass = ' file-preview-initial', cat, cap, ftr, | 
|                 ftype, asData = ifSet('previewAsData', config, data.previewAsData); | 
|             isDisabled = isDisabled === undefined ? true : isDisabled; | 
|             /** @namespace config.frameAttr */ | 
|             /** @namespace config.frameClass */ | 
|             /** @namespace config.filetype */ | 
|             if (!content) { | 
|                 return ''; | 
|             } | 
|             if (config && config.frameClass) { | 
|                 frameClass += ' ' + config.frameClass; | 
|             } | 
|             if (asData) { | 
|                 cat = data.previewAsData ? ifSet('type', config, data.previewFileType || 'generic') : 'generic'; | 
|                 cap = ifSet('caption', config); | 
|                 ftr = previewCache.footer(id, i, isDisabled, (config && config.size || null)); | 
|                 ftype = ifSet('filetype', config, cat); | 
|                 out = data.parseTemplate(cat, content, cap, ftype, previewId, ftr, ind, null); | 
|             } else { | 
|                 out = data.template | 
|                     .replace(/\{previewId}/g, previewId).replace(/\{frameClass}/g, frameClass) | 
|                     .replace(/\{fileindex}/g, ind).replace(/\{content}/g, data.content[i]) | 
|                     .replace(/\{template}/g, ifSet('type', config, data.previewFileType)) | 
|                     .replace(/\{footer}/g, previewCache.footer(id, i, isDisabled, (config && config.size || null))); | 
|             } | 
|             if (data.tags.length && data.tags[i]) { | 
|                 out = replaceTags(out, data.tags[i]); | 
|             } | 
|             if (!isEmpty(config) && !isEmpty(config.frameAttr)) { | 
|                 $tmp = $(document.createElement('div')).html(out); | 
|                 $tmp.find('.file-preview-initial').attr(config.frameAttr); | 
|                 out = $tmp.html(); | 
|                 $tmp.remove(); | 
|             } | 
|             return out; | 
|         }, | 
|         add: function (id, content, config, tags, append) { | 
|             var data = $.extend(true, {}, previewCache.data[id]), index; | 
|             if (!isArray(content)) { | 
|                 content = content.split(data.delimiter); | 
|             } | 
|             if (append) { | 
|                 index = data.content.push(content) - 1; | 
|                 data.config[index] = config; | 
|                 data.tags[index] = tags; | 
|             } else { | 
|                 index = content.length - 1; | 
|                 data.content = content; | 
|                 data.config = config; | 
|                 data.tags = tags; | 
|             } | 
|             previewCache.data[id] = data; | 
|             return index; | 
|         }, | 
|         set: function (id, content, config, tags, append) { | 
|             var data = $.extend(true, {}, previewCache.data[id]), i, chk; | 
|             if (!content || !content.length) { | 
|                 return; | 
|             } | 
|             if (!isArray(content)) { | 
|                 content = content.split(data.delimiter); | 
|             } | 
|             chk = content.filter(function (n) { | 
|                 return n !== null; | 
|             }); | 
|             if (!chk.length) { | 
|                 return; | 
|             } | 
|             if (data.content === undefined) { | 
|                 data.content = []; | 
|             } | 
|             if (data.config === undefined) { | 
|                 data.config = []; | 
|             } | 
|             if (data.tags === undefined) { | 
|                 data.tags = []; | 
|             } | 
|             if (append) { | 
|                 for (i = 0; i < content.length; i++) { | 
|                     if (content[i]) { | 
|                         data.content.push(content[i]); | 
|                     } | 
|                 } | 
|                 for (i = 0; i < config.length; i++) { | 
|                     if (config[i]) { | 
|                         data.config.push(config[i]); | 
|                     } | 
|                 } | 
|                 for (i = 0; i < tags.length; i++) { | 
|                     if (tags[i]) { | 
|                         data.tags.push(tags[i]); | 
|                     } | 
|                 } | 
|             } else { | 
|                 data.content = content; | 
|                 data.config = config; | 
|                 data.tags = tags; | 
|             } | 
|             previewCache.data[id] = data; | 
|         }, | 
|         unset: function (obj, index) { | 
|             var chk = previewCache.count(obj.id); | 
|             if (!chk) { | 
|                 return; | 
|             } | 
|             if (chk === 1) { | 
|                 previewCache.data[obj.id].content = []; | 
|                 previewCache.data[obj.id].config = []; | 
|                 previewCache.data[obj.id].tags = []; | 
|                 obj.initialPreview = []; | 
|                 obj.initialPreviewConfig = []; | 
|                 obj.initialPreviewThumbTags = []; | 
|                 return; | 
|             } | 
|   | 
|             previewCache.data[obj.id].content[index] = null; | 
|             previewCache.data[obj.id].config[index] = null; | 
|             previewCache.data[obj.id].tags[index] = null; | 
|         }, | 
|         out: function (id) { | 
|             var html = '', data = previewCache.data[id], caption, len = previewCache.count(id, true); | 
|             if (len === 0) { | 
|                 return {content: '', caption: ''}; | 
|             } | 
|             for (var i = 0; i < len; i++) { | 
|                 html += previewCache.get(id, i); | 
|             } | 
|             caption = data.msg(previewCache.count(id)); | 
|             return {content: '<div class="file-initial-thumbs">' + html + '</div>', caption: caption}; | 
|         }, | 
|         footer: function (id, i, isDisabled, size) { | 
|             var data = previewCache.data[id]; | 
|             isDisabled = isDisabled === undefined ? true : isDisabled; | 
|             if (data.config.length === 0 || isEmpty(data.config[i])) { | 
|                 return ''; | 
|             } | 
|             var config = data.config[i], caption = ifSet('caption', config), width = ifSet('width', config, 'auto'), | 
|                 url = ifSet('url', config, false), key = ifSet('key', config, null), | 
|                 showDel = ifSet('showDelete', config, true), showZoom = ifSet('showZoom', config, data.showZoom), | 
|                 showDrag = ifSet('showDrag', config, data.showDrag), disabled = (url === false) && isDisabled, | 
|                 actions = data.isDelete ? data.actions(false, showDel, showZoom, showDrag, disabled, url, key) : '', | 
|                 footer = data.footer.replace(/\{actions}/g, actions); | 
|             return footer.replace(/\{caption}/g, caption).replace(/\{size}/g, data.getSize(size)) | 
|                 .replace(/\{width}/g, width).replace(/\{indicator}/g, '').replace(/\{indicatorTitle}/g, ''); | 
|         } | 
|     }; | 
|     getNum = function (num, def) { | 
|         def = def || 0; | 
|         if (typeof num === "number") { | 
|             return num; | 
|         } | 
|         if (typeof num === "string") { | 
|             num = parseFloat(num); | 
|         } | 
|         return isNaN(num) ? def : num; | 
|     }; | 
|     hasFileAPISupport = function () { | 
|         return !!(window.File && window.FileReader); | 
|     }; | 
|     hasDragDropSupport = function () { | 
|         var div = document.createElement('div'); | 
|         /** @namespace div.draggable */ | 
|         /** @namespace div.ondragstart */ | 
|         /** @namespace div.ondrop */ | 
|         return !isIE(9) && (div.draggable !== undefined || (div.ondragstart !== undefined && div.ondrop !== undefined)); | 
|     }; | 
|     hasFileUploadSupport = function () { | 
|         return hasFileAPISupport() && window.FormData; | 
|     }; | 
|     addCss = function ($el, css) { | 
|         $el.removeClass(css).addClass(css); | 
|     }; | 
|     defaultFileActionSettings = { | 
|         showRemove: true, | 
|         showUpload: true, | 
|         showZoom: true, | 
|         showDrag: true, | 
|         removeIcon: '<i class="glyphicon glyphicon-trash text-danger"></i>', | 
|         removeClass: 'btn btn-xs btn-default', | 
|         removeTitle: 'Remove file', | 
|         uploadIcon: '<i class="glyphicon glyphicon-upload text-info"></i>', | 
|         uploadClass: 'btn btn-xs btn-default', | 
|         uploadTitle: 'Upload file', | 
|         zoomIcon: '<i class="glyphicon glyphicon-zoom-in"></i>', | 
|         zoomClass: 'btn btn-xs btn-default', | 
|         zoomTitle: 'View Details', | 
|         dragIcon: '<i class="glyphicon glyphicon-menu-hamburger"></i>', | 
|         dragClass: 'text-info', | 
|         dragTitle: 'Move / Rearrange', | 
|         dragSettings: {}, | 
|         indicatorNew: '<i class="glyphicon glyphicon-hand-down text-warning"></i>', | 
|         indicatorSuccess: '<i class="glyphicon glyphicon-ok-sign text-success"></i>', | 
|         indicatorError: '<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>', | 
|         indicatorLoading: '<i class="glyphicon glyphicon-hand-up text-muted"></i>', | 
|         indicatorNewTitle: 'Not uploaded yet', | 
|         indicatorSuccessTitle: 'Uploaded', | 
|         indicatorErrorTitle: 'Upload Error', | 
|         indicatorLoadingTitle: 'Uploading ...' | 
|     }; | 
|     tMain1 = '{preview}\n' + | 
|         '<div class="kv-upload-progress hide"></div>\n' + | 
|         '<div class="input-group {class}">\n' + | 
|         '   {caption}\n' + | 
|         '   <div class="input-group-btn">\n' + | 
|         '       {remove}\n' + | 
|         '       {cancel}\n' + | 
|         '       {upload}\n' + | 
|         '       {browse}\n' + | 
|         '   </div>\n' + | 
|         '</div>'; | 
|     tMain2 = '{preview}\n<div class="kv-upload-progress hide"></div>\n{remove}\n{cancel}\n{upload}\n{browse}\n'; | 
|     tPreview = '<div class="file-preview {class}">\n' + | 
|         '    {close}' + | 
|         '    <div class="{dropClass}">\n' + | 
|         '    <div class="file-preview-thumbnails">\n' + | 
|         '    </div>\n' + | 
|         '    <div class="clearfix"></div>' + | 
|         '    <div class="file-preview-status text-center text-success"></div>\n' + | 
|         '    <div class="kv-fileinput-error"></div>\n' + | 
|         '    </div>\n' + | 
|         '</div>'; | 
|     tClose = '<div class="close fileinput-remove">×</div>\n'; | 
|     tFileIcon = '<i class="glyphicon glyphicon-file kv-caption-icon"></i>'; | 
|     tCaption = '<div tabindex="500" class="form-control file-caption {class}">\n' + | 
|         '   <div class="file-caption-name"></div>\n' + | 
|         '</div>\n'; | 
|     //noinspection HtmlUnknownAttribute | 
|     tBtnDefault = '<button type="{type}" tabindex="500" title="{title}" class="{css}" {status}>{icon} {label}</button>'; | 
|     //noinspection HtmlUnknownAttribute | 
|     tBtnLink = '<a href="{href}" tabindex="500" title="{title}" class="{css}" {status}>{icon} {label}</a>'; | 
|     //noinspection HtmlUnknownAttribute | 
|     tBtnBrowse = '<div tabindex="500" class="{css}" {status}>{icon} {label}</div>'; | 
|     tModalMain = '<div id="' + MODAL_ID + '" class="file-zoom-dialog modal fade" tabindex="-1" aria-labelledby="' + | 
|         MODAL_ID + 'Label"></div>'; | 
|     tModal = '<div class="modal-dialog modal-lg" role="document">\n' + | 
|         '  <div class="modal-content">\n' + | 
|         '    <div class="modal-header">\n' + | 
|         '      <div class="kv-zoom-actions pull-right">{toggleheader}{fullscreen}{borderless}{close}</div>\n' + | 
|         '      <h3 class="modal-title">{heading} <small><span class="kv-zoom-title"></span></small></h3>\n' + | 
|         '    </div>\n' + | 
|         '    <div class="modal-body">\n' + | 
|         '      <div class="floating-buttons"></div>\n' + | 
|         '      <div class="kv-zoom-body file-zoom-content"></div>\n' + '{prev} {next}\n' + | 
|         '    </div>\n' + | 
|         '  </div>\n' + | 
|         '</div>\n'; | 
|     tProgress = '<div class="progress">\n' + | 
|         '    <div class="{class}" role="progressbar"' + | 
|         ' aria-valuenow="{percent}" aria-valuemin="0" aria-valuemax="100" style="width:{percent}%;">\n' + | 
|         '        {percent}%\n' + | 
|         '     </div>\n' + | 
|         '</div>'; | 
|     tSize = ' <br><samp>({sizeText})</samp>'; | 
|     tFooter = '<div class="file-thumbnail-footer">\n' + | 
|         '    <div class="file-footer-caption" title="{caption}">{caption}{size}</div>\n' + | 
|         '    {progress} {actions}\n' + | 
|         '</div>'; | 
|     tActions = '<div class="file-actions">\n' + | 
|         '    <div class="file-footer-buttons">\n' + | 
|         '        {upload} {delete} {zoom} {other}' + | 
|         '    </div>\n' + | 
|         '    {drag}\n' + | 
|         '    <div class="file-upload-indicator" title="{indicatorTitle}">{indicator}</div>\n' + | 
|         '    <div class="clearfix"></div>\n' + | 
|         '</div>'; | 
|     //noinspection HtmlUnknownAttribute | 
|     tActionDelete = '<button type="button" class="kv-file-remove {removeClass}" ' + 'title="{removeTitle}" {dataUrl}{dataKey}>{removeIcon}</button>\n'; | 
|     tActionUpload = '<button type="button" class="kv-file-upload {uploadClass}" title="{uploadTitle}">' + | 
|         '{uploadIcon}</button>'; | 
|     tActionZoom = '<button type="button" class="kv-file-zoom {zoomClass}" title="{zoomTitle}">{zoomIcon}</button>'; | 
|     tActionDrag = '<span class="file-drag-handle {dragClass}" title="{dragTitle}">{dragIcon}</span>'; | 
|     tTagBef = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' + | 
|         ' data-template="{template}"'; | 
|     tTagBef1 = tTagBef + '><div class="kv-file-content">\n'; | 
|     tTagBef2 = tTagBef + ' title="{caption}" ' + STYLE_SETTING + '><div class="kv-file-content">\n'; | 
|     tTagAft = '</div>{footer}\n</div>\n'; | 
|     tGeneric = '{content}\n'; | 
|     tHtml = '<div class="kv-preview-data file-preview-html" title="{caption}" ' + STYLE_SETTING + '>{data}</div>\n'; | 
|     tImage = '<img src="{data}" class="kv-preview-data file-preview-image" title="{caption}" alt="{caption}" ' + | 
|         STYLE_SETTING + '>\n'; | 
|     tText = '<textarea class="kv-preview-data file-preview-text" title="{caption}" readonly ' + STYLE_SETTING + | 
|         '>{data}</textarea>\n'; | 
|     tVideo = '<video class="kv-preview-data" width="{width}" height="{height}" controls>\n' + | 
|         '<source src="{data}" type="{type}">\n' + DEFAULT_PREVIEW + '\n</video>\n'; | 
|     tAudio = '<audio class="kv-preview-data" controls>\n<source src="' + '{data}' + '" type="{type}">\n' + | 
|         DEFAULT_PREVIEW + '\n</audio>\n'; | 
|     tFlash = '<object class="kv-preview-data file-object" type="application/x-shockwave-flash" ' + | 
|         'width="{width}" height="{height}" data="{data}">\n' + OBJECT_PARAMS + ' ' + DEFAULT_PREVIEW + '\n</object>\n'; | 
|     tObject = '<object class="kv-preview-data file-object" data="{data}" type="{type}" width="{width}" height="{height}">\n' + | 
|         '<param name="movie" value="{caption}" />\n' + OBJECT_PARAMS + ' ' + DEFAULT_PREVIEW + '\n</object>\n'; | 
|     tPdf = '<embed class="kv-preview-data" src="{data}" width="{width}" height="{height}" type="application/pdf">\n'; | 
|     tOther = '<div class="kv-preview-data file-preview-other-frame">\n' + DEFAULT_PREVIEW + '\n</div>\n'; | 
|     defaultLayoutTemplates = { | 
|         main1: tMain1, | 
|         main2: tMain2, | 
|         preview: tPreview, | 
|         close: tClose, | 
|         fileIcon: tFileIcon, | 
|         caption: tCaption, | 
|         modalMain: tModalMain, | 
|         modal: tModal, | 
|         progress: tProgress, | 
|         size: tSize, | 
|         footer: tFooter, | 
|         actions: tActions, | 
|         actionDelete: tActionDelete, | 
|         actionUpload: tActionUpload, | 
|         actionZoom: tActionZoom, | 
|         actionDrag: tActionDrag, | 
|         btnDefault: tBtnDefault, | 
|         btnLink: tBtnLink, | 
|         btnBrowse: tBtnBrowse | 
|     }; | 
|     defaultPreviewTemplates = { | 
|         generic: tTagBef1 + tGeneric + tTagAft, | 
|         html: tTagBef1 + tHtml + tTagAft, | 
|         image: tTagBef1 + tImage + tTagAft, | 
|         text: tTagBef1 + tText + tTagAft, | 
|         video: tTagBef2 + tVideo + tTagAft, | 
|         audio: tTagBef2 + tAudio + tTagAft, | 
|         flash: tTagBef2 + tFlash + tTagAft, | 
|         object: tTagBef2 + tObject + tTagAft, | 
|         pdf: tTagBef2 + tPdf + tTagAft, | 
|         other: tTagBef2 + tOther + tTagAft | 
|     }; | 
|     defaultPreviewTypes = ['image', 'html', 'text', 'video', 'audio', 'flash', 'pdf', 'object']; | 
|     defaultPreviewSettings = { | 
|         image: {width: "auto", height: "160px"}, | 
|         html: {width: "213px", height: "160px"}, | 
|         text: {width: "213px", height: "160px"}, | 
|         video: {width: "213px", height: "160px"}, | 
|         audio: {width: "213px", height: "80px"}, | 
|         flash: {width: "213px", height: "160px"}, | 
|         object: {width: "160px", height: "160px"}, | 
|         pdf: {width: "160px", height: "160px"}, | 
|         other: {width: "160px", height: "160px"} | 
|     }; | 
|     defaultPreviewZoomSettings = { | 
|         image: {width: "auto", height: "auto", 'max-width': "100%",'max-height': "100%"}, | 
|         html: {width: "100%", height: "100%", 'min-height': "480px"}, | 
|         text: {width: "100%", height: "100%", 'min-height': "480px"}, | 
|         video: {width: "auto", height: "100%", 'max-width': "100%"}, | 
|         audio: {width: "100%", height: "30px"}, | 
|         flash: {width: "auto", height: "480px"}, | 
|         object: {width: "auto", height: "100%", 'min-height': "480px"}, | 
|         pdf: {width: "100%", height: "100%", 'min-height': "480px"}, | 
|         other: {width: "auto", height: "100%", 'min-height': "480px"} | 
|     }; | 
|     defaultFileTypeSettings = { | 
|         image: function (vType, vName) { | 
|             return compare(vType, 'image.*') || compare(vName, /\.(gif|png|jpe?g)$/i); | 
|         }, | 
|         html: function (vType, vName) { | 
|             return compare(vType, 'text/html') || compare(vName, /\.(htm|html)$/i); | 
|         }, | 
|         text: function (vType, vName) { | 
|             return compare(vType, 'text.*') || compare(vName, /\.(xml|javascript)$/i) || | 
|                 compare(vName, /\.(txt|md|csv|nfo|ini|json|php|js|css)$/i); | 
|         }, | 
|         video: function (vType, vName) { | 
|             return compare(vType, 'video.*') && (compare(vType, /(ogg|mp4|mp?g|webm|3gp)$/i) || | 
|                 compare(vName, /\.(og?|mp4|webm|mp?g|3gp)$/i)); | 
|         }, | 
|         audio: function (vType, vName) { | 
|             return compare(vType, 'audio.*') && (compare(vName, /(ogg|mp3|mp?g|wav)$/i) || | 
|                 compare(vName, /\.(og?|mp3|mp?g|wav)$/i)); | 
|         }, | 
|         flash: function (vType, vName) { | 
|             return compare(vType, 'application/x-shockwave-flash', true) || compare(vName, /\.(swf)$/i); | 
|         }, | 
|         pdf: function (vType, vName) { | 
|             return compare(vType, 'application/pdf', true) || compare(vName, /\.(pdf)$/i); | 
|         }, | 
|         object: function () { | 
|             return true; | 
|         }, | 
|         other: function () { | 
|             return true; | 
|         } | 
|     }; | 
|     isEmpty = function (value, trim) { | 
|         return value === undefined || value === null || value.length === 0 || (trim && $.trim(value) === ''); | 
|     }; | 
|     isArray = function (a) { | 
|         return Array.isArray(a) || Object.prototype.toString.call(a) === '[object Array]'; | 
|     }; | 
|     ifSet = function (needle, haystack, def) { | 
|         def = def || ''; | 
|         return (haystack && typeof haystack === 'object' && needle in haystack) ? haystack[needle] : def; | 
|     }; | 
|     getElement = function (options, param, value) { | 
|         return (isEmpty(options) || isEmpty(options[param])) ? value : $(options[param]); | 
|     }; | 
|     uniqId = function () { | 
|         return Math.round(new Date().getTime() + (Math.random() * 100)); | 
|     }; | 
|     htmlEncode = function (str) { | 
|         return str.replace(/&/g, '&') | 
|             .replace(/</g, '<') | 
|             .replace(/>/g, '>') | 
|             .replace(/"/g, '"') | 
|             .replace(/'/g, '''); | 
|     }; | 
|     replaceTags = function (str, tags) { | 
|         var out = str; | 
|         if (!tags) { | 
|             return out; | 
|         } | 
|         $.each(tags, function (key, value) { | 
|             if (typeof value === "function") { | 
|                 value = value(); | 
|             } | 
|             out = out.split(key).join(value); | 
|         }); | 
|         return out; | 
|     }; | 
|     cleanMemory = function ($thumb) { | 
|         var data = $thumb.is('img') ? $thumb.attr('src') : $thumb.find('source').attr('src'); | 
|         /** @namespace objUrl.revokeObjectURL */ | 
|         objUrl.revokeObjectURL(data); | 
|     }; | 
|     findFileName = function (filePath) { | 
|         var sepIndex = filePath.lastIndexOf('/'); | 
|         if (sepIndex === -1) { | 
|             sepIndex = filePath.lastIndexOf('\\'); | 
|         } | 
|         return filePath.split(filePath.substring(sepIndex, sepIndex + 1)).pop(); | 
|     }; | 
|     checkFullScreen = function () { | 
|         //noinspection JSUnresolvedVariable | 
|         return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || | 
|             document.msFullscreenElement; | 
|     }; | 
|     toggleFullScreen = function (maximize) { | 
|         if (maximize && !checkFullScreen()) { | 
|             /** @namespace document.documentElement.requestFullscreen */ | 
|             /** @namespace document.documentElement.msRequestFullscreen */ | 
|             /** @namespace document.documentElement.mozRequestFullScreen */ | 
|             /** @namespace document.documentElement.webkitRequestFullscreen */ | 
|             /** @namespace Element.ALLOW_KEYBOARD_INPUT */ | 
|             if (document.documentElement.requestFullscreen) { | 
|                 document.documentElement.requestFullscreen(); | 
|             } else if (document.documentElement.msRequestFullscreen) { | 
|                 document.documentElement.msRequestFullscreen(); | 
|             } else if (document.documentElement.mozRequestFullScreen) { | 
|                 document.documentElement.mozRequestFullScreen(); | 
|             } else if (document.documentElement.webkitRequestFullscreen) { | 
|                 document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); | 
|             } | 
|         } else { | 
|             /** @namespace document.exitFullscreen */ | 
|             /** @namespace document.msExitFullscreen */ | 
|             /** @namespace document.mozCancelFullScreen */ | 
|             /** @namespace document.webkitExitFullscreen */ | 
|             if (document.exitFullscreen) { | 
|                 document.exitFullscreen(); | 
|             } else if (document.msExitFullscreen) { | 
|                 document.msExitFullscreen(); | 
|             } else if (document.mozCancelFullScreen) { | 
|                 document.mozCancelFullScreen(); | 
|             } else if (document.webkitExitFullscreen) { | 
|                 document.webkitExitFullscreen(); | 
|             } | 
|         } | 
|     }; | 
|     moveArray = function (arr, oldIndex, newIndex) { | 
|         if (newIndex >= arr.length) { | 
|             var k = newIndex - arr.length; | 
|             while ((k--) + 1) { | 
|                 arr.push(undefined); | 
|             } | 
|         } | 
|         arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]); | 
|         return arr; | 
|     }; | 
|     FileInput = function (element, options) { | 
|         var self = this; | 
|         self.$element = $(element); | 
|         if (!self._validate()) { | 
|             return; | 
|         } | 
|         self.isPreviewable = hasFileAPISupport(); | 
|         self.isIE9 = isIE(9); | 
|         self.isIE10 = isIE(10); | 
|         if (self.isPreviewable || self.isIE9) { | 
|             self._init(options); | 
|             self._listen(); | 
|         } else { | 
|             self.$element.removeClass('file-loading'); | 
|         } | 
|     }; | 
|     FileInput.prototype = { | 
|         constructor: FileInput, | 
|         _init: function (options) { | 
|             var self = this, $el = self.$element, t; | 
|             $.each(options, function (key, value) { | 
|                 switch (key) { | 
|                     case 'minFileCount': | 
|                     case 'maxFileCount': | 
|                     case 'maxFileSize': | 
|                         self[key] = getNum(value); | 
|                         break; | 
|                     default: | 
|                         self[key] = value; | 
|                         break; | 
|                 } | 
|             }); | 
|             self.fileInputCleared = false; | 
|             self.fileBatchCompleted = true; | 
|             if (!self.isPreviewable) { | 
|                 self.showPreview = false; | 
|             } | 
|             self.uploadFileAttr = !isEmpty($el.attr('name')) ? $el.attr('name') : 'file_data'; | 
|             self.reader = null; | 
|             self.formdata = {}; | 
|             self.clearStack(); | 
|             self.uploadCount = 0; | 
|             self.uploadStatus = {}; | 
|             self.uploadLog = []; | 
|             self.uploadAsyncCount = 0; | 
|             self.loadedImages = []; | 
|             self.totalImagesCount = 0; | 
|             self.ajaxRequests = []; | 
|             self.isError = false; | 
|             self.ajaxAborted = false; | 
|             self.cancelling = false; | 
|             t = self._getLayoutTemplate('progress'); | 
|             self.progressTemplate = t.replace('{class}', self.progressClass); | 
|             self.progressCompleteTemplate = t.replace('{class}', self.progressCompleteClass); | 
|             self.progressErrorTemplate = t.replace('{class}', self.progressErrorClass); | 
|             self.dropZoneEnabled = hasDragDropSupport() && self.dropZoneEnabled; | 
|             self.isDisabled = self.$element.attr('disabled') || self.$element.attr('readonly'); | 
|             self.isUploadable = hasFileUploadSupport() && !isEmpty(self.uploadUrl); | 
|             self.isClickable = self.browseOnZoneClick && self.showPreview && | 
|                 (self.isUploadable && self.dropZoneEnabled || !isEmpty(self.defaultPreviewContent)); | 
|             self.slug = typeof options.slugCallback === "function" ? options.slugCallback : self._slugDefault; | 
|             self.mainTemplate = self.showCaption ? self._getLayoutTemplate('main1') : self._getLayoutTemplate('main2'); | 
|             self.captionTemplate = self._getLayoutTemplate('caption'); | 
|             self.previewGenericTemplate = self._getPreviewTemplate('generic'); | 
|             if (self.resizeImage && (self.maxImageWidth || self.maxImageHeight)) { | 
|                 self.imageCanvas = document.createElement('canvas'); | 
|                 self.imageCanvasContext = self.imageCanvas.getContext('2d'); | 
|             } | 
|             if (isEmpty(self.$element.attr('id'))) { | 
|                 self.$element.attr('id', uniqId()); | 
|             } | 
|             if (self.$container === undefined) { | 
|                 self.$container = self._createContainer(); | 
|             } else { | 
|                 self._refreshContainer(); | 
|             } | 
|             self.$dropZone = self.$container.find('.file-drop-zone'); | 
|             self.$progress = self.$container.find('.kv-upload-progress'); | 
|             self.$btnUpload = self.$container.find('.fileinput-upload'); | 
|             self.$captionContainer = getElement(options, 'elCaptionContainer', self.$container.find('.file-caption')); | 
|             self.$caption = getElement(options, 'elCaptionText', self.$container.find('.file-caption-name')); | 
|             self.$previewContainer = getElement(options, 'elPreviewContainer', self.$container.find('.file-preview')); | 
|             self.$preview = getElement(options, 'elPreviewImage', self.$container.find('.file-preview-thumbnails')); | 
|             self.$previewStatus = getElement(options, 'elPreviewStatus', self.$container.find('.file-preview-status')); | 
|             self.$errorContainer = getElement(options, 'elErrorContainer', | 
|                 self.$previewContainer.find('.kv-fileinput-error')); | 
|             if (!isEmpty(self.msgErrorClass)) { | 
|                 addCss(self.$errorContainer, self.msgErrorClass); | 
|             } | 
|             self.$errorContainer.hide(); | 
|             self.fileActionSettings = $.extend(true, defaultFileActionSettings, options.fileActionSettings); | 
|             self.previewInitId = "preview-" + uniqId(); | 
|             self.id = self.$element.attr('id'); | 
|             previewCache.init(self); | 
|             self._initPreview(true); | 
|             self._initPreviewActions(); | 
|             self.options = options; | 
|             self._setFileDropZoneTitle(); | 
|             self.$element.removeClass('file-loading'); | 
|             if (self.$element.attr('disabled')) { | 
|                 self.disable(); | 
|             } | 
|             self._initZoom(); | 
|         }, | 
|         _validate: function () { | 
|             var self = this, $exception; | 
|             if (self.$element.attr('type') === 'file') { | 
|                 return true; | 
|             } | 
|             $exception = '<div class="help-block alert alert-warning">' + | 
|                 '<h4>Invalid Input Type</h4>' + | 
|                 'You must set an input <code>type = file</code> for <b>bootstrap-fileinput</b> plugin to initialize.' + | 
|                 '</div>'; | 
|             self.$element.after($exception); | 
|             return false; | 
|         }, | 
|         _errorsExist: function () { | 
|             var self = this, $err; | 
|             if (self.$errorContainer.find('li').length) { | 
|                 return true; | 
|             } | 
|             $err = $(document.createElement('div')).html(self.$errorContainer.html()); | 
|             $err.find('span.kv-error-close').remove(); | 
|             $err.find('ul').remove(); | 
|             return $.trim($err.text()).length ? true : false; | 
|         }, | 
|         _errorHandler: function (evt, caption) { | 
|             var self = this, err = evt.target.error; | 
|             /** @namespace err.NOT_FOUND_ERR */ | 
|             /** @namespace err.SECURITY_ERR */ | 
|             /** @namespace err.NOT_READABLE_ERR */ | 
|             if (err.code === err.NOT_FOUND_ERR) { | 
|                 self._showError(self.msgFileNotFound.replace('{name}', caption)); | 
|             } else if (err.code === err.SECURITY_ERR) { | 
|                 self._showError(self.msgFileSecured.replace('{name}', caption)); | 
|             } else if (err.code === err.NOT_READABLE_ERR) { | 
|                 self._showError(self.msgFileNotReadable.replace('{name}', caption)); | 
|             } else if (err.code === err.ABORT_ERR) { | 
|                 self._showError(self.msgFilePreviewAborted.replace('{name}', caption)); | 
|             } else { | 
|                 self._showError(self.msgFilePreviewError.replace('{name}', caption)); | 
|             } | 
|         }, | 
|         _addError: function (msg) { | 
|             var self = this, $error = self.$errorContainer; | 
|             if (msg && $error.length) { | 
|                 $error.html(self.errorCloseButton + msg); | 
|                 handler($error.find('.kv-error-close'), 'click', function () { | 
|                     $error.fadeOut('slow'); | 
|                 }); | 
|             } | 
|         }, | 
|         _resetErrors: function (fade) { | 
|             var self = this, $error = self.$errorContainer; | 
|             self.isError = false; | 
|             self.$container.removeClass('has-error'); | 
|             $error.html(''); | 
|             if (fade) { | 
|                 $error.fadeOut('slow'); | 
|             } else { | 
|                 $error.hide(); | 
|             } | 
|         }, | 
|         _showFolderError: function (folders) { | 
|             var self = this, $error = self.$errorContainer, msg; | 
|             if (!folders) { | 
|                 return; | 
|             } | 
|             msg = self.msgFoldersNotAllowed.replace(/\{n}/g, folders); | 
|             self._addError(msg); | 
|             addCss(self.$container, 'has-error'); | 
|             $error.fadeIn(800); | 
|             self._raise('filefoldererror', [folders, msg]); | 
|         }, | 
|         _showUploadError: function (msg, params, event) { | 
|             var self = this, $error = self.$errorContainer, ev = event || 'fileuploaderror', e = params && params.id ? | 
|             '<li data-file-id="' + params.id + '">' + msg + '</li>' : '<li>' + msg + '</li>'; | 
|             if ($error.find('ul').length === 0) { | 
|                 self._addError('<ul>' + e + '</ul>'); | 
|             } else { | 
|                 $error.find('ul').append(e); | 
|             } | 
|             $error.fadeIn(800); | 
|             self._raise(ev, [params, msg]); | 
|             self.$container.removeClass('file-input-new'); | 
|             addCss(self.$container, 'has-error'); | 
|             return true; | 
|         }, | 
|         _showError: function (msg, params, event) { | 
|             var self = this, $error = self.$errorContainer, ev = event || 'fileerror'; | 
|             params = params || {}; | 
|             params.reader = self.reader; | 
|             self._addError(msg); | 
|             $error.fadeIn(800); | 
|             self._raise(ev, [params, msg]); | 
|             if (!self.isUploadable) { | 
|                 self._clearFileInput(); | 
|             } | 
|             self.$container.removeClass('file-input-new'); | 
|             addCss(self.$container, 'has-error'); | 
|             self.$btnUpload.attr('disabled', true); | 
|             return true; | 
|         }, | 
|         _noFilesError: function (params) { | 
|             var self = this, label = self.minFileCount > 1 ? self.filePlural : self.fileSingle, | 
|                 msg = self.msgFilesTooLess.replace('{n}', self.minFileCount).replace('{files}', label), | 
|                 $error = self.$errorContainer; | 
|             self._addError(msg); | 
|             self.isError = true; | 
|             self._updateFileDetails(0); | 
|             $error.fadeIn(800); | 
|             self._raise('fileerror', [params, msg]); | 
|             self._clearFileInput(); | 
|             addCss(self.$container, 'has-error'); | 
|         }, | 
|         _parseError: function (jqXHR, errorThrown, fileName) { | 
|             /** @namespace jqXHR.responseJSON */ | 
|             var self = this, errMsg = $.trim(errorThrown + ''), | 
|                 dot = errMsg.slice(-1) === '.' ? '' : '.', | 
|                 text = jqXHR.responseJSON !== undefined && jqXHR.responseJSON.error !== undefined ? | 
|                     jqXHR.responseJSON.error : jqXHR.responseText; | 
|             if (self.cancelling && self.msgUploadAborted) { | 
|                 errMsg = self.msgUploadAborted; | 
|             } | 
|             if (self.showAjaxErrorDetails && text) { | 
|                 text = $.trim(text.replace(/\n\s*\n/g, '\n')); | 
|                 text = text.length > 0 ? '<pre>' + text + '</pre>' : ''; | 
|                 errMsg += dot + text; | 
|             } else { | 
|                 errMsg += dot; | 
|             } | 
|             self.cancelling = false; | 
|             return fileName ? '<b>' + fileName + ': </b>' + errMsg : errMsg; | 
|         }, | 
|         _parseFileType: function (file) { | 
|             var self = this, isValid, vType, cat, i; | 
|             for (i = 0; i < defaultPreviewTypes.length; i += 1) { | 
|                 cat = defaultPreviewTypes[i]; | 
|                 isValid = ifSet(cat, self.fileTypeSettings, defaultFileTypeSettings[cat]); | 
|                 vType = isValid(file.type, file.name) ? cat : ''; | 
|                 if (!isEmpty(vType)) { | 
|                     return vType; | 
|                 } | 
|             } | 
|             return 'other'; | 
|         }, | 
|         _parseFilePreviewIcon: function (content, fname) { | 
|             var self = this, proceed, ext, icn = self.previewFileIcon; | 
|             if (fname && fname.indexOf('.') > -1) { | 
|                 ext = fname.split('.').pop(); | 
|                 if (self.previewFileIconSettings && self.previewFileIconSettings[ext]) { | 
|                     icn = self.previewFileIconSettings[ext]; | 
|                 } | 
|                 if (self.previewFileExtSettings) { | 
|                     $.each(self.previewFileExtSettings, function (key, func) { | 
|                         if (self.previewFileIconSettings[key] && func(ext)) { | 
|                             icn = self.previewFileIconSettings[key]; | 
|                             return; | 
|                         } | 
|                         proceed = true; | 
|                     }); | 
|                 } | 
|             } | 
|             if (content.indexOf('{previewFileIcon}') > -1) { | 
|                 return content.replace(/\{previewFileIconClass}/g, self.previewFileIconClass).replace( | 
|                     /\{previewFileIcon}/g, icn); | 
|             } | 
|             return content; | 
|         }, | 
|         _raise: function (event, params) { | 
|             var self = this, e = $.Event(event); | 
|             if (params !== undefined) { | 
|                 self.$element.trigger(e, params); | 
|             } else { | 
|                 self.$element.trigger(e); | 
|             } | 
|             if (e.isDefaultPrevented()) { | 
|                 return false; | 
|             } | 
|             if (!e.result) { | 
|                 return e.result; | 
|             } | 
|             switch (event) { | 
|                 // ignore these events | 
|                 case 'filebatchuploadcomplete': | 
|                 case 'filebatchuploadsuccess': | 
|                 case 'fileuploaded': | 
|                 case 'fileclear': | 
|                 case 'filecleared': | 
|                 case 'filereset': | 
|                 case 'fileerror': | 
|                 case 'filefoldererror': | 
|                 case 'fileuploaderror': | 
|                 case 'filebatchuploaderror': | 
|                 case 'filedeleteerror': | 
|                 case 'filecustomerror': | 
|                 case 'filesuccessremove': | 
|                     break; | 
|                 // receive data response via `filecustomerror` event` | 
|                 default: | 
|                     self.ajaxAborted = e.result; | 
|                     break; | 
|             } | 
|             return true; | 
|         }, | 
|         _listenFullScreen: function (isFullScreen) { | 
|             var self = this, $modal = self.$modal, $btnFull, $btnBord; | 
|             if (!$modal || !$modal.length) { | 
|                 return; | 
|             } | 
|             $btnFull = $modal && $modal.find('.btn-fullscreen'); | 
|             $btnBord = $modal && $modal.find('.btn-borderless'); | 
|             if (!$btnFull.length || !$btnBord.length) { | 
|                 return; | 
|             } | 
|             $btnFull.removeClass('active').attr('aria-pressed', 'false'); | 
|             $btnBord.removeClass('active').attr('aria-pressed', 'false'); | 
|             if (isFullScreen) { | 
|                 $btnFull.addClass('active').attr('aria-pressed', 'true'); | 
|             } else { | 
|                 $btnBord.addClass('active').attr('aria-pressed', 'true'); | 
|             } | 
|             if ($modal.hasClass('file-zoom-fullscreen')) { | 
|                 self._maximizeZoomDialog(); | 
|             } else { | 
|                 if (isFullScreen) { | 
|                     self._maximizeZoomDialog(); | 
|                 } else { | 
|                     $btnBord.removeClass('active').attr('aria-pressed', 'false'); | 
|                 } | 
|             } | 
|         }, | 
|         _listen: function () { | 
|             var self = this, $el = self.$element, $form = $el.closest('form'), $cont = self.$container; | 
|             handler($el, 'change', $.proxy(self._change, self)); | 
|             if (self.showBrowse) { | 
|                 handler(self.$btnFile, 'click', $.proxy(self._browse, self)); | 
|             } | 
|             handler($form, 'reset', $.proxy(self.reset, self)); | 
|             handler($cont.find('.fileinput-remove:not([disabled])'), 'click', $.proxy(self.clear, self)); | 
|             handler($cont.find('.fileinput-cancel'), 'click', $.proxy(self.cancel, self)); | 
|             self._initDragDrop(); | 
|             if (!self.isUploadable) { | 
|                 handler($form, 'submit', $.proxy(self._submitForm, self)); | 
|             } | 
|             handler(self.$container.find('.fileinput-upload'), 'click', $.proxy(self._uploadClick, self)); | 
|             handler($(window), 'resize', function () { | 
|                 self._listenFullScreen(screen.width === window.innerWidth && screen.height === window.innerHeight); | 
|             }); | 
|             handler($(document), 'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange', | 
|                 function () { | 
|                     self._listenFullScreen(checkFullScreen()); | 
|                 }); | 
|             self._initClickable(); | 
|         }, | 
|         _initClickable: function () { | 
|             var self = this, $zone; | 
|             if (!self.isClickable) { | 
|                 return; | 
|             } | 
|             $zone = self.isUploadable ? self.$dropZone : self.$preview.find('.file-default-preview'); | 
|             addCss($zone, 'clickable'); | 
|             $zone.attr('tabindex', -1); | 
|             handler($zone, 'click', function (e) { | 
|                 var $target = $(e.target); | 
|                 if (!$target.parents('.file-preview-thumbnails').length || $target.parents( | 
|                         '.file-default-preview').length) { | 
|                     self.$element.trigger('click'); | 
|                     $zone.blur(); | 
|                 } | 
|             }); | 
|         }, | 
|         _initDragDrop: function () { | 
|             var self = this, $zone = self.$dropZone; | 
|             if (self.isUploadable && self.dropZoneEnabled && self.showPreview) { | 
|                 handler($zone, 'dragenter dragover', $.proxy(self._zoneDragEnter, self)); | 
|                 handler($zone, 'dragleave', $.proxy(self._zoneDragLeave, self)); | 
|                 handler($zone, 'drop', $.proxy(self._zoneDrop, self)); | 
|                 handler($(document), 'dragenter dragover drop', self._zoneDragDropInit); | 
|             } | 
|         }, | 
|         _zoneDragDropInit: function (e) { | 
|             e.stopPropagation(); | 
|             e.preventDefault(); | 
|         }, | 
|         _zoneDragEnter: function (e) { | 
|             var self = this, hasFiles = $.inArray('Files', e.originalEvent.dataTransfer.types) > -1; | 
|             self._zoneDragDropInit(e); | 
|             if (self.isDisabled || !hasFiles) { | 
|                 e.originalEvent.dataTransfer.effectAllowed = 'none'; | 
|                 e.originalEvent.dataTransfer.dropEffect = 'none'; | 
|                 return; | 
|             } | 
|             addCss(self.$dropZone, 'file-highlighted'); | 
|         }, | 
|         _zoneDragLeave: function (e) { | 
|             var self = this; | 
|             self._zoneDragDropInit(e); | 
|             if (self.isDisabled) { | 
|                 return; | 
|             } | 
|             self.$dropZone.removeClass('file-highlighted'); | 
|         }, | 
|         _zoneDrop: function (e) { | 
|             var self = this; | 
|             e.preventDefault(); | 
|             /** @namespace e.originalEvent.dataTransfer */ | 
|             if (self.isDisabled || isEmpty(e.originalEvent.dataTransfer.files)) { | 
|                 return; | 
|             } | 
|             self._change(e, 'dragdrop'); | 
|             self.$dropZone.removeClass('file-highlighted'); | 
|         }, | 
|         _uploadClick: function (e) { | 
|             var self = this, $btn = self.$container.find('.fileinput-upload'), $form, | 
|                 isEnabled = !$btn.hasClass('disabled') && isEmpty($btn.attr('disabled')); | 
|             if (e && e.isDefaultPrevented()) { | 
|                 return; | 
|             } | 
|             if (!self.isUploadable) { | 
|                 if (isEnabled && $btn.attr('type') !== 'submit') { | 
|                     $form = $btn.closest('form'); | 
|                     // downgrade to normal form submit if possible | 
|                     if ($form.length) { | 
|                         $form.trigger('submit'); | 
|                     } | 
|                     e.preventDefault(); | 
|                 } | 
|                 return; | 
|             } | 
|             e.preventDefault(); | 
|             if (isEnabled) { | 
|                 self.upload(); | 
|             } | 
|         }, | 
|         _submitForm: function () { | 
|             var self = this, $el = self.$element, files = $el.get(0).files; | 
|             if (files && self.minFileCount > 0 && self._getFileCount(files.length) < self.minFileCount) { | 
|                 self._noFilesError({}); | 
|                 return false; | 
|             } | 
|             return !self._abort({}); | 
|         }, | 
|         _clearPreview: function () { | 
|             var self = this, $thumbs = !self.showUploadedThumbs ? self.$preview.find('.file-preview-frame') : | 
|                 self.$preview.find('.file-preview-frame:not(.file-preview-success)'); | 
|             $thumbs.remove(); | 
|             if (!self.$preview.find('.file-preview-frame').length || !self.showPreview) { | 
|                 self._resetUpload(); | 
|             } | 
|             self._validateDefaultPreview(); | 
|         }, | 
|         _initSortable: function () { | 
|             var self = this, $preview = self.$preview, $el, settings; | 
|             if (!window.KvSortable) { | 
|                 return; | 
|             } | 
|             $el = $preview.find('.file-initial-thumbs'); | 
|             //noinspection JSUnusedGlobalSymbols | 
|             settings = { | 
|                 handle: '.drag-handle-init', | 
|                 dataIdAttr: 'data-preview-id', | 
|                 draggable: '.file-preview-initial', | 
|                 onSort: function (e) { | 
|                     var oldIndex = e.oldIndex, newIndex = e.newIndex; | 
|                     self.initialPreview = moveArray(self.initialPreview, oldIndex, newIndex); | 
|                     self.initialPreviewConfig = moveArray(self.initialPreviewConfig, oldIndex, newIndex); | 
|                     previewCache.init(self); | 
|                     for(var i = 0; i < self.initialPreviewConfig.length; i++) { | 
|                         if(self.initialPreviewConfig[i] !== null) { | 
|                             var key = self.initialPreviewConfig[i].key; | 
|                             var $frame = $(".kv-file-remove[data-key='" + key + "']"); | 
|                             $frame = $frame.closest('.file-preview-frame'); | 
|                             $frame.attr('data-fileindex', 'init_'+i); | 
|                             $frame.data('fileindex', 'init_'+i); | 
|                         } | 
|                     } | 
|                     self._raise('filesorted', { | 
|                         previewId: $(e.item).attr('id'), | 
|                         'oldIndex': oldIndex, | 
|                         'newIndex': newIndex, | 
|                         stack: self.initialPreviewConfig | 
|                     }); | 
|                 } | 
|             }; | 
|             if ($el.data('kvsortable')) { | 
|                 $el.kvsortable('destroy'); | 
|             } | 
|             $.extend(true, settings, self.fileActionSettings.dragSettings); | 
|             $el.kvsortable(settings); | 
|         }, | 
|         _initPreview: function (isInit) { | 
|             var self = this, cap = self.initialCaption || '', out; | 
|             if (!previewCache.count(self.id)) { | 
|                 self._clearPreview(); | 
|                 if (isInit) { | 
|                     self._setCaption(cap); | 
|                 } else { | 
|                     self._initCaption(); | 
|                 } | 
|                 return; | 
|             } | 
|             out = previewCache.out(self.id); | 
|             cap = isInit && self.initialCaption ? self.initialCaption : out.caption; | 
|             self.$preview.html(out.content); | 
|             self._setCaption(cap); | 
|             self._initSortable(); | 
|             if (!isEmpty(out.content)) { | 
|                 self.$container.removeClass('file-input-new'); | 
|             } | 
|         }, | 
|         _getZoomButton: function (type) { | 
|             var self = this, label = self.previewZoomButtonIcons[type], css = self.previewZoomButtonClasses[type], | 
|                 title = ' title="' + (self.previewZoomButtonTitles[type] || '') + '" ', | 
|                 params = title + (type === 'close' ? ' data-dismiss="modal" aria-hidden="true"' : ''); | 
|             if (type === 'fullscreen' || type === 'borderless' || type === 'toggleheader') { | 
|                 params += ' data-toggle="button" aria-pressed="false" autocomplete="off"'; | 
|             } | 
|             return '<button type="button" class="' + css + ' btn-' + type + '"' + params + '>' + label + '</button>'; | 
|         }, | 
|         _getModalContent: function () { | 
|             var self = this; | 
|             return self._getLayoutTemplate('modal') | 
|                 .replace(/\{heading}/g, self.msgZoomModalHeading) | 
|                 .replace(/\{prev}/g, self._getZoomButton('prev')) | 
|                 .replace(/\{next}/g, self._getZoomButton('next')) | 
|                 .replace(/\{toggleheader}/g, self._getZoomButton('toggleheader')) | 
|                 .replace(/\{fullscreen}/g, self._getZoomButton('fullscreen')) | 
|                 .replace(/\{borderless}/g, self._getZoomButton('borderless')) | 
|                 .replace(/\{close}/g, self._getZoomButton('close')); | 
|         }, | 
|         _listenModalEvent: function (event) { | 
|             var self = this, $modal = self.$modal, getParams = function (e) { | 
|                 return { | 
|                     sourceEvent: e, | 
|                     previewId: $modal.data('previewId'), | 
|                     modal: $modal | 
|                 }; | 
|             }; | 
|             $modal.on(event + '.bs.modal', function (e) { | 
|                 var $btnFull = $modal.find('.btn-fullscreen'), $btnBord = $modal.find('.btn-borderless'); | 
|                 self._raise('filezoom' + event, getParams(e)); | 
|                 if (event === 'shown') { | 
|                     $btnBord.removeClass('active').attr('aria-pressed', 'false'); | 
|                     $btnFull.removeClass('active').attr('aria-pressed', 'false'); | 
|                     if ($modal.hasClass('file-zoom-fullscreen')) { | 
|                         self._maximizeZoomDialog(); | 
|                         if (checkFullScreen()) { | 
|                             $btnFull.addClass('active').attr('aria-pressed', 'true'); | 
|                         } else { | 
|                             $btnBord.addClass('active').attr('aria-pressed', 'true'); | 
|                         } | 
|                     } | 
|                 } | 
|             }); | 
|         }, | 
|         _initZoom: function () { | 
|             var self = this, $dialog, modalMain = self._getLayoutTemplate('modalMain'), modalId = '#' + MODAL_ID; | 
|             self.$modal = $(modalId); | 
|             if (!self.$modal || !self.$modal.length) { | 
|                 $dialog = $(document.createElement('div')).html(modalMain).insertAfter(self.$container); | 
|                 self.$modal = $('#' + MODAL_ID).insertBefore($dialog); | 
|                 $dialog.remove(); | 
|             } | 
|             self.$modal.html(self._getModalContent()); | 
|             self._listenModalEvent('show'); | 
|             self._listenModalEvent('shown'); | 
|             self._listenModalEvent('hide'); | 
|             self._listenModalEvent('hidden'); | 
|             self._listenModalEvent('loaded'); | 
|         }, | 
|         _initZoomButtons: function () { | 
|             var self = this, previewId = self.$modal.data('previewId') || '', $first, $last, | 
|                 frames = self.$preview.find('.file-preview-frame').toArray(), len = frames.length, | 
|                 $prev = self.$modal.find('.btn-prev'), $next = self.$modal.find('.btn-next'); | 
|   | 
|             if (!len) { | 
|                 return; | 
|             } | 
|             $first = $(frames[0]); | 
|             $last = $(frames[len - 1]); | 
|             $prev.removeAttr('disabled'); | 
|             $next.removeAttr('disabled'); | 
|             if ($first.length && $first.attr('id') === previewId) { | 
|                 $prev.attr('disabled', true); | 
|             } | 
|             if ($last.length && $last.attr('id') === previewId) { | 
|                 $next.attr('disabled', true); | 
|             } | 
|         }, | 
|         _maximizeZoomDialog: function () { | 
|             var self = this, $modal = self.$modal, $head = $modal.find('.modal-header:visible'), | 
|                 $foot = $modal.find('.modal-footer:visible'), $body = $modal.find('.modal-body'), | 
|                 h = $(window).height(), diff = 0; | 
|             $modal.addClass('file-zoom-fullscreen'); | 
|             if ($head && $head.length) { | 
|                 h -= $head.outerHeight(true); | 
|             } | 
|             if ($foot && $foot.length) { | 
|                 h -= $foot.outerHeight(true); | 
|             } | 
|             if ($body && $body.length) { | 
|                 diff = $body.outerHeight(true) - $body.height(); | 
|                 h -= diff; | 
|             } | 
|             $modal.find('.kv-zoom-body').height(h); | 
|         }, | 
|         _resizeZoomDialog: function (fullScreen) { | 
|             var self = this, $modal = self.$modal, $btnFull = $modal.find('.btn-fullscreen'), | 
|                 $btnBord = $modal.find('.btn-borderless'); | 
|             if ($modal.hasClass('file-zoom-fullscreen')) { | 
|                 toggleFullScreen(false); | 
|                 if (!fullScreen) { | 
|                     if (!$btnFull.hasClass('active')) { | 
|                         $modal.removeClass('file-zoom-fullscreen'); | 
|                         self.$modal.find('.kv-zoom-body').css('height', self.zoomModalHeight); | 
|                     } else { | 
|                         $btnFull.removeClass('active').attr('aria-pressed', 'false'); | 
|                     } | 
|                 } else { | 
|                     if (!$btnFull.hasClass('active')) { | 
|                         $modal.removeClass('file-zoom-fullscreen'); | 
|                         self._resizeZoomDialog(true); | 
|                         if ($btnBord.hasClass('active')) { | 
|                             $btnBord.removeClass('active').attr('aria-pressed', 'false'); | 
|                         } | 
|                     } | 
|                 } | 
|             } else { | 
|                 if (!fullScreen) { | 
|                     self._maximizeZoomDialog(); | 
|                     return; | 
|                 } | 
|                 toggleFullScreen(true); | 
|             } | 
|             $modal.focus(); | 
|         }, | 
|         _setZoomContent: function ($preview, animate) { | 
|             var self = this, $content, tmplt, body, title, $body, $dataEl, config, previewId = $preview.attr('id'), | 
|                 $modal = self.$modal, $prev = $modal.find('.btn-prev'), $next = $modal.find('.btn-next'), $tmp, | 
|                 $btnFull = $modal.find('.btn-fullscreen'), $btnBord = $modal.find('.btn-borderless'), | 
|                 $btnTogh = $modal.find('.btn-toggleheader'); | 
|             tmplt = $preview.data('template') || 'generic'; | 
|             $content = $preview.find('.kv-file-content'); | 
|             body = $content.length ? $content.html() : ''; | 
|             title = $preview.find('.file-footer-caption').text() || ''; | 
|             $modal.find('.kv-zoom-title').html(title); | 
|             $body = $modal.find('.kv-zoom-body'); | 
|             if (animate) { | 
|                 $tmp = $body.clone().insertAfter($body); | 
|                 $body.html(body).hide(); | 
|                 $tmp.fadeOut('fast', function () { | 
|                     $body.fadeIn('fast'); | 
|                     $tmp.remove(); | 
|                 }); | 
|             } else { | 
|                 $body.html(body); | 
|             } | 
|             config = self.previewZoomSettings[tmplt]; | 
|             if (config) { | 
|                 $dataEl = $body.find('.kv-preview-data'); | 
|                 addCss($dataEl, 'file-zoom-detail'); | 
|                 $.each(config, function (key, value) { | 
|                     $dataEl.css(key, value); | 
|                     if (($dataEl.attr('width') && key === 'width') || ($dataEl.attr('height') && key === 'height')) { | 
|                         $dataEl.removeAttr(key); | 
|                     } | 
|                 }); | 
|             } | 
|             $modal.data('previewId', previewId); | 
|             handler($prev, 'click', function () { | 
|                 self._zoomSlideShow('prev', previewId); | 
|             }); | 
|             handler($next, 'click', function () { | 
|                 self._zoomSlideShow('next', previewId); | 
|             }); | 
|             handler($btnFull, 'click', function () { | 
|                 self._resizeZoomDialog(true); | 
|             }); | 
|             handler($btnBord, 'click', function () { | 
|                 self._resizeZoomDialog(false); | 
|             }); | 
|             handler($btnTogh, 'click', function () { | 
|                 var $header = $modal.find('.modal-header'), $floatBar = $modal.find('.modal-body .floating-buttons'), | 
|                     ht, $actions = $header.find('.kv-zoom-actions'), resize = function (height) { | 
|                         var $body = self.$modal.find('.kv-zoom-body'), h = self.zoomModalHeight; | 
|                         if ($modal.hasClass('file-zoom-fullscreen')) { | 
|                             h = $body.outerHeight(true); | 
|                             if (!height) { | 
|                                 h = h - $header.outerHeight(true); | 
|                             } | 
|                         } | 
|                         $body.css('height', height ? h + height : h); | 
|                     }; | 
|                 if ($header.is(':visible')) { | 
|                     ht = $header.outerHeight(true); | 
|                     $header.slideUp('slow', function () { | 
|                         $actions.find('.btn').appendTo($floatBar); | 
|                         resize(ht); | 
|                     }); | 
|                 } else { | 
|                     $floatBar.find('.btn').appendTo($actions); | 
|                     $header.slideDown('slow', function () { | 
|                         resize(); | 
|                     }); | 
|                 } | 
|                 $modal.focus(); | 
|             }); | 
|             handler($modal, 'keydown', function (e) { | 
|                 var key = e.which || e.keyCode; | 
|                 if (key === 37 && !$prev.attr('disabled')) { | 
|                     self._zoomSlideShow('prev', previewId); | 
|                 } | 
|                 if (key === 39 && !$next.attr('disabled')) { | 
|                     self._zoomSlideShow('next', previewId); | 
|                 } | 
|             }); | 
|         }, | 
|         _zoomPreview: function ($btn) { | 
|             var self = this, $preview; | 
|             if (!$btn.length) { | 
|                 throw 'Cannot zoom to detailed preview!'; | 
|             } | 
|             self.$modal.html(self._getModalContent()); | 
|             $preview = $btn.closest('.file-preview-frame'); | 
|             self._setZoomContent($preview); | 
|             self.$modal.modal('show'); | 
|             self._initZoomButtons(); | 
|         }, | 
|         _zoomSlideShow: function (dir, previewId) { | 
|             var self = this, $btn = self.$modal.find('.kv-zoom-actions .btn-' + dir), $targFrame, i, | 
|                 frames = self.$preview.find('.file-preview-frame').toArray(), len = frames.length, out; | 
|             if ($btn.attr('disabled')) { | 
|                 return; | 
|             } | 
|             for (i = 0; i < len; i++) { | 
|                 if ($(frames[i]).attr('id') === previewId) { | 
|                     out = dir === 'prev' ? i - 1 : i + 1; | 
|                     break; | 
|                 } | 
|             } | 
|             if (out < 0 || out >= len || !frames[out]) { | 
|                 return; | 
|             } | 
|             $targFrame = $(frames[out]); | 
|             if ($targFrame.length) { | 
|                 self._setZoomContent($targFrame, true); | 
|             } | 
|             self._initZoomButtons(); | 
|             self._raise('filezoom' + dir, {'previewId': previewId, modal: self.$modal}); | 
|         }, | 
|         _initZoomButton: function () { | 
|             var self = this; | 
|             self.$preview.find('.kv-file-zoom').each(function () { | 
|                 var $el = $(this); | 
|                 handler($el, 'click', function () { | 
|                     self._zoomPreview($el); | 
|                 }); | 
|             }); | 
|         }, | 
|         _initPreviewActions: function () { | 
|             var self = this, deleteExtraData = self.deleteExtraData || {}, | 
|                 resetProgress = function () { | 
|                     var hasFiles = self.isUploadable ? previewCache.count(self.id) : self.$element.get(0).files.length; | 
|                     if (self.$preview.find('.kv-file-remove').length === 0 && !hasFiles) { | 
|                         self.reset(); | 
|                         self.initialCaption = ''; | 
|                     } | 
|                 }; | 
|             self._initZoomButton(); | 
|             self.$preview.find('.kv-file-remove').each(function () { | 
|                 var $el = $(this), vUrl = $el.data('url') || self.deleteUrl, vKey = $el.data('key'); | 
|                 if (isEmpty(vUrl) || vKey === undefined) { | 
|                     return; | 
|                 } | 
|                 var $frame = $el.closest('.file-preview-frame'), cache = previewCache.data[self.id], | 
|                     settings, params, index = $frame.data('fileindex'), config, extraData; | 
|                 index = parseInt(index.replace('init_', '')); | 
|                 config = isEmpty(cache.config) && isEmpty(cache.config[index]) ? null : cache.config[index]; | 
|                 extraData = isEmpty(config) || isEmpty(config.extra) ? deleteExtraData : config.extra; | 
|                 if (typeof extraData === "function") { | 
|                     extraData = extraData(); | 
|                 } | 
|                 params = {id: $el.attr('id'), key: vKey, extra: extraData}; | 
|                 settings = $.extend(true, {}, { | 
|                     url: vUrl, | 
|                     type: 'POST', | 
|                     dataType: 'json', | 
|                     data: $.extend(true, {}, {key: vKey}, extraData), | 
|                     beforeSend: function (jqXHR) { | 
|                         self.ajaxAborted = false; | 
|                         self._raise('filepredelete', [vKey, jqXHR, extraData]); | 
|                         if (self.ajaxAborted) { | 
|                             jqXHR.abort(); | 
|                         } else { | 
|                             addCss($frame, 'file-uploading'); | 
|                             addCss($el, 'disabled'); | 
|                         } | 
|                     }, | 
|                     success: function (data, textStatus, jqXHR) { | 
|                         var n, cap; | 
|                         if (isEmpty(data) || isEmpty(data.error)) { | 
|                             previewCache.init(self); | 
|                             index = parseInt(($frame.data('fileindex')).replace('init_', '')); | 
|                             previewCache.unset(self, index); | 
|                             n = previewCache.count(self.id); | 
|                             cap = n > 0 ? self._getMsgSelected(n) : ''; | 
|                             self._raise('filedeleted', [vKey, jqXHR, extraData]); | 
|                             self._setCaption(cap); | 
|                         } else { | 
|                             params.jqXHR = jqXHR; | 
|                             params.response = data; | 
|                             self._showError(data.error, params, 'filedeleteerror'); | 
|                             $frame.removeClass('file-uploading'); | 
|                             $el.removeClass('disabled'); | 
|                             resetProgress(); | 
|                             return; | 
|                         } | 
|                         $frame.removeClass('file-uploading').addClass('file-deleted'); | 
|                         $frame.fadeOut('slow', function () { | 
|                             self._clearObjects($frame); | 
|                             $frame.remove(); | 
|                             resetProgress(); | 
|                             if (!n && self.getFileStack().length === 0) { | 
|                                 self._setCaption(''); | 
|                                 self.reset(); | 
|                             } | 
|                         }); | 
|                     }, | 
|                     error: function (jqXHR, textStatus, errorThrown) { | 
|                         var errMsg = self._parseError(jqXHR, errorThrown); | 
|                         params.jqXHR = jqXHR; | 
|                         params.response = {}; | 
|                         self._showError(errMsg, params, 'filedeleteerror'); | 
|                         $frame.removeClass('file-uploading'); | 
|                         resetProgress(); | 
|                     } | 
|                 }, self.ajaxDeleteSettings); | 
|                 handler($el, 'click', function () { | 
|                     if (!self._validateMinCount()) { | 
|                         return false; | 
|                     } | 
|                     $.ajax(settings); | 
|                 }); | 
|             }); | 
|         }, | 
|         _clearObjects: function ($el) { | 
|             $el.find('video audio').each(function () { | 
|                 this.pause(); | 
|                 $(this).remove(); | 
|             }); | 
|             $el.find('img object div').each(function () { | 
|                 $(this).remove(); | 
|             }); | 
|         }, | 
|         _clearFileInput: function () { | 
|             var self = this, $el = self.$element, $srcFrm, $tmpFrm, $tmpEl; | 
|             self.fileInputCleared = true; | 
|             if (isEmpty($el.val())) { | 
|                 return; | 
|             } | 
|             // Fix for IE ver < 11, that does not clear file inputs. Requires a sequence of steps to prevent IE | 
|             // crashing but still allow clearing of the file input. | 
|             if (self.isIE9 || self.isIE10) { | 
|                 $srcFrm = $el.closest('form'); | 
|                 $tmpFrm = $(document.createElement('form')); | 
|                 $tmpEl = $(document.createElement('div')); | 
|                 $el.before($tmpEl); | 
|                 if ($srcFrm.length) { | 
|                     $srcFrm.after($tmpFrm); | 
|                 } else { | 
|                     $tmpEl.after($tmpFrm); | 
|                 } | 
|                 $tmpFrm.append($el).trigger('reset'); | 
|                 $tmpEl.before($el).remove(); | 
|                 $tmpFrm.remove(); | 
|             } else { // normal input clear behavior for other sane browsers | 
|                 $el.val(''); | 
|             } | 
|         }, | 
|         _resetUpload: function () { | 
|             var self = this; | 
|             self.uploadCache = {content: [], config: [], tags: [], append: true}; | 
|             self.uploadCount = 0; | 
|             self.uploadStatus = {}; | 
|             self.uploadLog = []; | 
|             self.uploadAsyncCount = 0; | 
|             self.loadedImages = []; | 
|             self.totalImagesCount = 0; | 
|             self.$btnUpload.removeAttr('disabled'); | 
|             self._setProgress(0); | 
|             addCss(self.$progress, 'hide'); | 
|             self._resetErrors(false); | 
|             self.ajaxAborted = false; | 
|             self.ajaxRequests = []; | 
|             self._resetCanvas(); | 
|         }, | 
|         _resetCanvas: function () { | 
|             var self = this; | 
|             if (self.canvas && self.imageCanvasContext) { | 
|                 self.imageCanvasContext.clearRect(0, 0, self.canvas.width, self.canvas.height); | 
|             } | 
|         }, | 
|         _hasInitialPreview: function () { | 
|             var self = this; | 
|             return !self.overwriteInitial && previewCache.count(self.id); | 
|         }, | 
|         _resetPreview: function () { | 
|             var self = this, out, cap; | 
|             if (previewCache.count(self.id)) { | 
|                 out = previewCache.out(self.id); | 
|                 self.$preview.html(out.content); | 
|                 cap = self.initialCaption ? self.initialCaption : out.caption; | 
|                 self._setCaption(cap); | 
|             } else { | 
|                 self._clearPreview(); | 
|                 self._initCaption(); | 
|             } | 
|             if (self.showPreview) { | 
|                 self._initZoom(); | 
|                 self._initSortable(); | 
|             } | 
|         }, | 
|         _clearDefaultPreview: function () { | 
|             var self = this; | 
|             self.$preview.find('.file-default-preview').remove(); | 
|         }, | 
|         _validateDefaultPreview: function () { | 
|             var self = this; | 
|             if (!self.showPreview || isEmpty(self.defaultPreviewContent)) { | 
|                 return; | 
|             } | 
|             self.$preview.html('<div class="file-default-preview">' + self.defaultPreviewContent + '</div>'); | 
|             self.$container.removeClass('file-input-new'); | 
|             self._initClickable(); | 
|         }, | 
|         _resetPreviewThumbs: function (isAjax) { | 
|             var self = this, out; | 
|             if (isAjax) { | 
|                 self._clearPreview(); | 
|                 self.clearStack(); | 
|                 return; | 
|             } | 
|             if (self._hasInitialPreview()) { | 
|                 out = previewCache.out(self.id); | 
|                 self.$preview.html(out.content); | 
|                 self._setCaption(out.caption); | 
|                 self._initPreviewActions(); | 
|             } else { | 
|                 self._clearPreview(); | 
|             } | 
|         }, | 
|         _getLayoutTemplate: function (t) { | 
|             var self = this, | 
|                 template = ifSet(t, self.layoutTemplates, defaultLayoutTemplates[t]); | 
|             if (isEmpty(self.customLayoutTags)) { | 
|                 return template; | 
|             } | 
|             return replaceTags(template, self.customLayoutTags); | 
|         }, | 
|         _getPreviewTemplate: function (t) { | 
|             var self = this, | 
|                 template = ifSet(t, self.previewTemplates, defaultPreviewTemplates[t]); | 
|             if (isEmpty(self.customPreviewTags)) { | 
|                 return template; | 
|             } | 
|             return replaceTags(template, self.customPreviewTags); | 
|         }, | 
|         _getOutData: function (jqXHR, responseData, filesData) { | 
|             var self = this; | 
|             jqXHR = jqXHR || {}; | 
|             responseData = responseData || {}; | 
|             filesData = filesData || self.filestack.slice(0) || {}; | 
|             return { | 
|                 form: self.formdata, | 
|                 files: filesData, | 
|                 filenames: self.filenames, | 
|                 filescount: self.getFilesCount(), | 
|                 extra: self._getExtraData(), | 
|                 response: responseData, | 
|                 reader: self.reader, | 
|                 jqXHR: jqXHR | 
|             }; | 
|         }, | 
|         _getMsgSelected: function (n) { | 
|             var self = this, strFiles = n === 1 ? self.fileSingle : self.filePlural; | 
|             return n > 0 ? self.msgSelected.replace('{n}', n).replace('{files}', strFiles) : self.msgNoFilesSelected; | 
|         }, | 
|         _getThumbs: function (css) { | 
|             css = css || ''; | 
|             return this.$preview.find('.file-preview-frame:not(.file-preview-initial)' + css); | 
|         }, | 
|         _getExtraData: function (previewId, index) { | 
|             var self = this, data = self.uploadExtraData; | 
|             if (typeof self.uploadExtraData === "function") { | 
|                 data = self.uploadExtraData(previewId, index); | 
|             } | 
|             return data; | 
|         }, | 
|         _initXhr: function (xhrobj, previewId, fileCount) { | 
|             var self = this; | 
|             if (xhrobj.upload) { | 
|                 xhrobj.upload.addEventListener('progress', function (event) { | 
|                     var pct = 0, total = event.total, position = event.loaded || event.position; | 
|                     /** @namespace event.lengthComputable */ | 
|                     if (event.lengthComputable) { | 
|                         pct = Math.floor(position / total * 100); | 
|                     } | 
|                     if (previewId) { | 
|                         self._setAsyncUploadStatus(previewId, pct, fileCount); | 
|                     } else { | 
|                         self._setProgress(pct); | 
|                     } | 
|                 }, false); | 
|             } | 
|             return xhrobj; | 
|         }, | 
|         _ajaxSubmit: function (fnBefore, fnSuccess, fnComplete, fnError, previewId, index) { | 
|             var self = this, settings; | 
|             self._raise('filepreajax', [previewId, index]); | 
|             self._uploadExtra(previewId, index); | 
|             settings = $.extend(true, {}, { | 
|                 xhr: function () { | 
|                     var xhrobj = $.ajaxSettings.xhr(); | 
|                     return self._initXhr(xhrobj, previewId, self.getFileStack().length); | 
|                 }, | 
|                 url: self.uploadUrl, | 
|                 type: 'POST', | 
|                 dataType: 'json', | 
|                 data: self.formdata, | 
|                 cache: false, | 
|                 processData: false, | 
|                 contentType: false, | 
|                 beforeSend: fnBefore, | 
|                 success: fnSuccess, | 
|                 complete: fnComplete, | 
|                 error: fnError | 
|             }, self.ajaxSettings); | 
|             self.ajaxRequests.push($.ajax(settings)); | 
|         }, | 
|         _initUploadSuccess: function (out, $thumb, allFiles) { | 
|             var self = this, append, data, index, $newThumb, content, config, tags, i, | 
|                 mergeArray = function (prop, content) { | 
|                     if (!(self[prop] instanceof Array)) { | 
|                         self[prop] = []; | 
|                     } | 
|                     if (content && content.length) { | 
|                         self[prop] = self[prop].concat(content); | 
|                     } | 
|                 }; | 
|             if (!self.showPreview || typeof out !== 'object' || $.isEmptyObject(out)) { | 
|                 return; | 
|             } | 
|             if (out.initialPreview !== undefined && out.initialPreview.length > 0) { | 
|                 self.hasInitData = true; | 
|                 content = out.initialPreview || []; | 
|                 config = out.initialPreviewConfig || []; | 
|                 tags = out.initialPreviewThumbTags || []; | 
|                 append = out.append === undefined || out.append ? true : false; | 
|                 if (content.length > 0 && !isArray(content)) { | 
|                     content = content.split(self.initialPreviewDelimiter); | 
|                 } | 
|                 self.overwriteInitial = false; | 
|                 mergeArray('initialPreview', content); | 
|                 mergeArray('initialPreviewConfig', config); | 
|                 mergeArray('initialPreviewThumbTags', tags); | 
|                 if ($thumb !== undefined) { | 
|                     if (!allFiles) { | 
|                         index = previewCache.add(self.id, content, config[0], tags[0], append); | 
|                         data = previewCache.get(self.id, index, false); | 
|                         $newThumb = $(data).hide(); | 
|                         $thumb.after($newThumb).fadeOut('slow', function () { | 
|                             $newThumb.fadeIn('slow').css('display:inline-block'); | 
|                             self._initPreviewActions(); | 
|                             self._clearFileInput(); | 
|                             $thumb.remove(); | 
|                         }); | 
|                     } else { | 
|                         i = $thumb.attr('data-fileindex'); | 
|                         self.uploadCache.content[i] = content[0]; | 
|                         self.uploadCache.config[i] = config[0] || []; | 
|                         self.uploadCache.tags[i] = tags[0] || []; | 
|                         self.uploadCache.append = append; | 
|                     } | 
|                 } else { | 
|                     previewCache.set(self.id, content, config, tags, append); | 
|                     self._initPreview(); | 
|                     self._initPreviewActions(); | 
|                 } | 
|             } | 
|         }, | 
|         _initSuccessThumbs: function () { | 
|             var self = this; | 
|             if (!self.showPreview) { | 
|                 return; | 
|             } | 
|             self._getThumbs('.file-preview-success').each(function () { | 
|                 var $thumb = $(this), $remove = $thumb.find('.kv-file-remove'); | 
|                 $remove.removeAttr('disabled'); | 
|                 handler($remove, 'click', function () { | 
|                     var out = self._raise('filesuccessremove', [$thumb.attr('id'), $thumb.data('fileindex')]); | 
|                     cleanMemory($thumb); | 
|                     if (out === false) { | 
|                         return; | 
|                     } | 
|                     $thumb.fadeOut('slow', function () { | 
|                         $thumb.remove(); | 
|                         if (!self.$preview.find('.file-preview-frame').length) { | 
|                             self.reset(); | 
|                         } | 
|                     }); | 
|                 }); | 
|             }); | 
|         }, | 
|         _checkAsyncComplete: function () { | 
|             var self = this, previewId, i; | 
|             for (i = 0; i < self.filestack.length; i++) { | 
|                 if (self.filestack[i]) { | 
|                     previewId = self.previewInitId + "-" + i; | 
|                     if ($.inArray(previewId, self.uploadLog) === -1) { | 
|                         return false; | 
|                     } | 
|                 } | 
|             } | 
|             return (self.uploadAsyncCount === self.uploadLog.length); | 
|         }, | 
|         _uploadExtra: function (previewId, index) { | 
|             var self = this, data = self._getExtraData(previewId, index); | 
|             if (data.length === 0) { | 
|                 return; | 
|             } | 
|             $.each(data, function (key, value) { | 
|                 self.formdata.append(key, value); | 
|             }); | 
|         }, | 
|         _uploadSingle: function (i, files, allFiles) { | 
|             var self = this, total = self.getFileStack().length, formdata = new FormData(), outData, | 
|                 previewId = self.previewInitId + "-" + i, $thumb, chkComplete, $btnUpload, $btnDelete, | 
|                 hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData), | 
|                 fnBefore, fnSuccess, fnComplete, fnError, updateUploadLog, params = {id: previewId, index: i}; | 
|             self.formdata = formdata; | 
|             if (self.showPreview) { | 
|                 $thumb = $('#' + previewId + ':not(.file-preview-initial)'); | 
|                 $btnUpload = $thumb.find('.kv-file-upload'); | 
|                 $btnDelete = $thumb.find('.kv-file-remove'); | 
|                 $('#' + previewId).find('.file-thumb-progress').removeClass('hide'); | 
|             } | 
|             if (total === 0 || !hasPostData || ($btnUpload && $btnUpload.hasClass('disabled')) || self._abort(params)) { | 
|                 return; | 
|             } | 
|             updateUploadLog = function (i, previewId) { | 
|                 self.updateStack(i, undefined); | 
|                 self.uploadLog.push(previewId); | 
|                 if (self._checkAsyncComplete()) { | 
|                     self.fileBatchCompleted = true; | 
|                 } | 
|             }; | 
|             chkComplete = function () { | 
|                 var u = self.uploadCache; | 
|                 if (!self.fileBatchCompleted) { | 
|                     return; | 
|                 } | 
|                 setTimeout(function () { | 
|                     if (self.showPreview) { | 
|                         previewCache.set(self.id, u.content, u.config, u.tags, u.append); | 
|                         if (self.hasInitData) { | 
|                             self._initPreview(); | 
|                             self._initPreviewActions(); | 
|                         } | 
|                     } | 
|                     self.unlock(); | 
|                     self._clearFileInput(); | 
|                     self._raise('filebatchuploadcomplete', [self.filestack, self._getExtraData()]); | 
|                     self.uploadCount = 0; | 
|                     self.uploadStatus = {}; | 
|                     self.uploadLog = []; | 
|                     self._setProgress(101); | 
|                 }, 100); | 
|             }; | 
|             fnBefore = function (jqXHR) { | 
|                 outData = self._getOutData(jqXHR); | 
|                 self.fileBatchCompleted = false; | 
|                 if (self.showPreview) { | 
|                     if (!$thumb.hasClass('file-preview-success')) { | 
|                         self._setThumbStatus($thumb, 'Loading'); | 
|                         addCss($thumb, 'file-uploading'); | 
|                     } | 
|                     $btnUpload.attr('disabled', true); | 
|                     $btnDelete.attr('disabled', true); | 
|                 } | 
|                 if (!allFiles) { | 
|                     self.lock(); | 
|                 } | 
|                 self._raise('filepreupload', [outData, previewId, i]); | 
|                 $.extend(true, params, outData); | 
|                 if (self._abort(params)) { | 
|                     jqXHR.abort(); | 
|                     self._setProgressCancelled(); | 
|                 } | 
|             }; | 
|             fnSuccess = function (data, textStatus, jqXHR) { | 
|                 var pid = self.showPreview && $thumb.attr('id') ? $thumb.attr('id') : previewId; | 
|                 outData = self._getOutData(jqXHR, data); | 
|                 $.extend(true, params, outData); | 
|                 setTimeout(function () { | 
|                     if (isEmpty(data) || isEmpty(data.error)) { | 
|                         if (self.showPreview) { | 
|                             self._setThumbStatus($thumb, 'Success'); | 
|                             $btnUpload.hide(); | 
|                             self._initUploadSuccess(data, $thumb, allFiles); | 
|                         } | 
|                         self._raise('fileuploaded', [outData, pid, i]); | 
|                         if (!allFiles) { | 
|                             self.updateStack(i, undefined); | 
|                         } else { | 
|                             updateUploadLog(i, pid); | 
|                         } | 
|                     } else { | 
|                         self._showUploadError(data.error, params); | 
|                         self._setPreviewError($thumb, i); | 
|                         if (allFiles) { | 
|                             updateUploadLog(i, pid); | 
|                         } | 
|                     } | 
|                 }, 100); | 
|             }; | 
|             fnComplete = function () { | 
|                 setTimeout(function () { | 
|                     if (self.showPreview) { | 
|                         $btnUpload.removeAttr('disabled'); | 
|                         $btnDelete.removeAttr('disabled'); | 
|                         $thumb.removeClass('file-uploading'); | 
|                         self._setProgress(101, $('#' + previewId).find('.file-thumb-progress')); | 
|                     } | 
|                     if (!allFiles) { | 
|                         self.unlock(false); | 
|                         self._clearFileInput(); | 
|                     } else { | 
|                         chkComplete(); | 
|                     } | 
|                     self._initSuccessThumbs(); | 
|                 }, 100); | 
|             }; | 
|             fnError = function (jqXHR, textStatus, errorThrown) { | 
|                 var errMsg = self._parseError(jqXHR, errorThrown, (allFiles ? files[i].name : null)); | 
|                 setTimeout(function () { | 
|                     if (allFiles) { | 
|                         updateUploadLog(i, previewId); | 
|                     } | 
|                     self.uploadStatus[previewId] = 100; | 
|                     self._setPreviewError($thumb, i); | 
|                     $.extend(true, params, self._getOutData(jqXHR)); | 
|                     self._showUploadError(errMsg, params); | 
|                 }, 100); | 
|             }; | 
|             formdata.append(self.uploadFileAttr, files[i], self.filenames[i]); | 
|             formdata.append('file_id', i); | 
|             self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, previewId, i); | 
|         }, | 
|         _uploadBatch: function () { | 
|             var self = this, files = self.filestack, total = files.length, params = {}, fnBefore, fnSuccess, fnError, | 
|                 fnComplete, hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData), | 
|                 setAllUploaded; | 
|             self.formdata = new FormData(); | 
|             if (total === 0 || !hasPostData || self._abort(params)) { | 
|                 return; | 
|             } | 
|             setAllUploaded = function () { | 
|                 $.each(files, function (key) { | 
|                     self.updateStack(key, undefined); | 
|                 }); | 
|                 self._clearFileInput(); | 
|             }; | 
|             fnBefore = function (jqXHR) { | 
|                 self.lock(); | 
|                 var outData = self._getOutData(jqXHR); | 
|                 if (self.showPreview) { | 
|                     self._getThumbs().each(function () { | 
|                         var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload'), | 
|                             $btnDelete = $thumb.find('.kv-file-remove'); | 
|                         if (!$thumb.hasClass('file-preview-success')) { | 
|                             self._setThumbStatus($thumb, 'Loading'); | 
|                             addCss($thumb, 'file-uploading'); | 
|                         } | 
|                         $btnUpload.attr('disabled', true); | 
|                         $btnDelete.attr('disabled', true); | 
|                     }); | 
|                 } | 
|                 self._raise('filebatchpreupload', [outData]); | 
|                 if (self._abort(outData)) { | 
|                     jqXHR.abort(); | 
|                     self._setProgressCancelled(); | 
|                 } | 
|             }; | 
|             fnSuccess = function (data, textStatus, jqXHR) { | 
|                 /** @namespace data.errorkeys */ | 
|                 var outData = self._getOutData(jqXHR, data), $thumbs = self._getThumbs(':not(.file-preview-error)'), key = 0, | 
|                     keys = isEmpty(data) || isEmpty(data.errorkeys) ? [] : data.errorkeys; | 
|                 if (isEmpty(data) || isEmpty(data.error)) { | 
|                     self._raise('filebatchuploadsuccess', [outData]); | 
|                     setAllUploaded(); | 
|                     if (self.showPreview) { | 
|                         $thumbs.each(function () { | 
|                             var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload'); | 
|                             $thumb.find('.kv-file-upload').hide(); | 
|                             self._setThumbStatus($thumb, 'Success'); | 
|                             $thumb.removeClass('file-uploading'); | 
|                             $btnUpload.removeAttr('disabled'); | 
|                         }); | 
|                         self._initUploadSuccess(data); | 
|                     } else { | 
|                         self.reset(); | 
|                     } | 
|                 } else { | 
|                     if (self.showPreview) { | 
|                         $thumbs.each(function () { | 
|                             var $thumb = $(this), $btnDelete = $thumb.find('.kv-file-remove'), | 
|                                 $btnUpload = $thumb.find('.kv-file-upload'); | 
|                             $thumb.removeClass('file-uploading'); | 
|                             $btnUpload.removeAttr('disabled'); | 
|                             $btnDelete.removeAttr('disabled'); | 
|                             if (keys.length === 0) { | 
|                                 self._setPreviewError($thumb); | 
|                                 return; | 
|                             } | 
|                             if ($.inArray(key, keys) !== -1) { | 
|                                 self._setPreviewError($thumb); | 
|                             } else { | 
|                                 $thumb.find('.kv-file-upload').hide(); | 
|                                 self._setThumbStatus($thumb, 'Success'); | 
|                                 self.updateStack(key, undefined); | 
|                             } | 
|                             key++; | 
|                         }); | 
|                         self._initUploadSuccess(data); | 
|                     } | 
|                     self._showUploadError(data.error, outData, 'filebatchuploaderror'); | 
|                 } | 
|             }; | 
|             fnComplete = function () { | 
|                 self._setProgress(101); | 
|                 self.unlock(); | 
|                 self._initSuccessThumbs(); | 
|                 self._clearFileInput(); | 
|                 self._raise('filebatchuploadcomplete', [self.filestack, self._getExtraData()]); | 
|             }; | 
|             fnError = function (jqXHR, textStatus, errorThrown) { | 
|                 var outData = self._getOutData(jqXHR), errMsg = self._parseError(jqXHR, errorThrown); | 
|                 self._showUploadError(errMsg, outData, 'filebatchuploaderror'); | 
|                 self.uploadFileCount = total - 1; | 
|                 if (!self.showPreview) { | 
|                     return; | 
|                 } | 
|                 self._getThumbs().each(function () { | 
|                     var $thumb = $(this), key = $thumb.attr('data-fileindex'); | 
|                     $thumb.removeClass('file-uploading'); | 
|                     if (self.filestack[key] !== undefined) { | 
|                         self._setPreviewError($thumb); | 
|                     } | 
|                 }); | 
|                 self._getThumbs().removeClass('file-uploading'); | 
|                 self._getThumbs(' .kv-file-upload').removeAttr('disabled'); | 
|                 self._getThumbs(' .kv-file-delete').removeAttr('disabled'); | 
|             }; | 
|             $.each(files, function (key, data) { | 
|                 if (!isEmpty(files[key])) { | 
|                     self.formdata.append(self.uploadFileAttr, data, self.filenames[key]); | 
|                 } | 
|             }); | 
|             self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError); | 
|         }, | 
|         _uploadExtraOnly: function () { | 
|             var self = this, params = {}, fnBefore, fnSuccess, fnComplete, fnError; | 
|             self.formdata = new FormData(); | 
|             if (self._abort(params)) { | 
|                 return; | 
|             } | 
|             fnBefore = function (jqXHR) { | 
|                 self.lock(); | 
|                 var outData = self._getOutData(jqXHR); | 
|                 self._raise('filebatchpreupload', [outData]); | 
|                 self._setProgress(50); | 
|                 params.data = outData; | 
|                 params.xhr = jqXHR; | 
|                 if (self._abort(params)) { | 
|                     jqXHR.abort(); | 
|                     self._setProgressCancelled(); | 
|                 } | 
|             }; | 
|             fnSuccess = function (data, textStatus, jqXHR) { | 
|                 var outData = self._getOutData(jqXHR, data); | 
|                 if (isEmpty(data) || isEmpty(data.error)) { | 
|                     self._raise('filebatchuploadsuccess', [outData]); | 
|                     self._clearFileInput(); | 
|                     self._initUploadSuccess(data); | 
|                 } else { | 
|                     self._showUploadError(data.error, outData, 'filebatchuploaderror'); | 
|                 } | 
|             }; | 
|             fnComplete = function () { | 
|                 self._setProgress(101); | 
|                 self.unlock(); | 
|                 self._clearFileInput(); | 
|                 self._raise('filebatchuploadcomplete', [self.filestack, self._getExtraData()]); | 
|             }; | 
|             fnError = function (jqXHR, textStatus, errorThrown) { | 
|                 var outData = self._getOutData(jqXHR), errMsg = self._parseError(jqXHR, errorThrown); | 
|                 params.data = outData; | 
|                 self._showUploadError(errMsg, outData, 'filebatchuploaderror'); | 
|             }; | 
|             self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError); | 
|         }, | 
|         _initFileActions: function () { | 
|             var self = this; | 
|             if (!self.showPreview) { | 
|                 return; | 
|             } | 
|             self._initZoomButton(); | 
|             self.$preview.find('.kv-file-remove').each(function () { | 
|                 var $el = $(this), $frame = $el.closest('.file-preview-frame'), hasError, | 
|                     id = $frame.attr('id'), ind = $frame.attr('data-fileindex'), n, cap, status; | 
|                 handler($el, 'click', function () { | 
|                     status = self._raise('filepreremove', [id, ind]); | 
|                     if (status === false || !self._validateMinCount()) { | 
|                         return false; | 
|                     } | 
|                     hasError = $frame.hasClass('file-preview-error'); | 
|                     cleanMemory($frame); | 
|                     $frame.fadeOut('slow', function () { | 
|                         self.updateStack(ind, undefined); | 
|                         self._clearObjects($frame); | 
|                         $frame.remove(); | 
|                         if (id && hasError) { | 
|                             self.$errorContainer.find('li[data-file-id="' + id + '"]').fadeOut('fast', function () { | 
|                                 $(this).remove(); | 
|                                 if (!self._errorsExist()) { | 
|                                     self._resetErrors(); | 
|                                 } | 
|                             }); | 
|                         } | 
|                         self._clearFileInput(); | 
|                         var filestack = self.getFileStack(true), chk = previewCache.count(self.id), | 
|                             len = filestack.length, | 
|                             hasThumb = self.showPreview && self.$preview.find('.file-preview-frame').length; | 
|                         if (len === 0 && chk === 0 && !hasThumb) { | 
|                             self.reset(); | 
|                         } else { | 
|                             n = chk + len; | 
|                             cap = n > 1 ? self._getMsgSelected(n) : (filestack[0] ? self._getFileNames()[0] : ''); | 
|                             self._setCaption(cap); | 
|                         } | 
|                         self._raise('fileremoved', [id, ind]); | 
|                     }); | 
|                 }); | 
|             }); | 
|             self.$preview.find('.kv-file-upload').each(function () { | 
|                 var $el = $(this); | 
|                 handler($el, 'click', function () { | 
|                     var $frame = $el.closest('.file-preview-frame'), | 
|                         ind = $frame.attr('data-fileindex'); | 
|                     if (!$frame.hasClass('file-preview-error')) { | 
|                         self._uploadSingle(ind, self.filestack, false); | 
|                     } | 
|                 }); | 
|             }); | 
|         }, | 
|         _hideFileIcon: function () { | 
|             if (this.overwriteInitial) { | 
|                 this.$captionContainer.find('.kv-caption-icon').hide(); | 
|             } | 
|         }, | 
|         _showFileIcon: function () { | 
|             this.$captionContainer.find('.kv-caption-icon').show(); | 
|         }, | 
|         _getSize: function (bytes) { | 
|             var self = this, size = parseFloat(bytes); | 
|             if (!bytes || !size || isNaN(bytes) || isNaN(size)) { | 
|                 return self._getLayoutTemplate('size').replace('{sizeText}', '0.00 KB'); | 
|             } | 
|             var  i, func = self.fileSizeGetter, sizes, out; | 
|             if (typeof func === 'function') { | 
|                 out = func(bytes); | 
|             } else { | 
|                 i = Math.floor(Math.log(size) / Math.log(1024)); | 
|                 sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; | 
|                 out = (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i]; | 
|             } | 
|             return self._getLayoutTemplate('size').replace('{sizeText}', out); | 
|         }, | 
|         _generatePreviewTemplate: function (cat, data, fname, ftype, previewId, isError, size, frameClass, foot, ind) { | 
|             var self = this, tmplt = self._getPreviewTemplate(cat), content, sText, css = frameClass || '', | 
|                 config = ifSet(cat, self.previewSettings, defaultPreviewSettings[cat]), caption = self.slug(fname), | 
|                 footer = foot || self._renderFileFooter(caption, size, config.width, isError); | 
|             ind = ind || previewId.slice(previewId.lastIndexOf('-') + 1); | 
|             tmplt = self._parseFilePreviewIcon(tmplt, fname); | 
|             if (cat === 'text' || cat === 'html') { | 
|                 sText = cat === 'text' ? htmlEncode(data) : data; | 
|                 content = tmplt.replace(/\{previewId}/g, previewId).replace(/\{caption}/g, caption) | 
|                     .replace(/\{width}/g, config.width).replace(/\{height}/g, config.height) | 
|                     .replace(/\{frameClass}/g, css).replace(/\{cat}/g, ftype) | 
|                     .replace(/\{footer}/g, footer).replace(/\{fileindex}/g, ind) | 
|                     .replace(/\{data}/g, sText).replace(/\{template}/g, cat); | 
|             } else { | 
|                 content = tmplt.replace(/\{previewId}/g, previewId).replace(/\{caption}/g, caption) | 
|                     .replace(/\{frameClass}/g, css).replace(/\{type}/g, ftype).replace(/\{fileindex}/g, ind) | 
|                     .replace(/\{width}/g, config.width).replace(/\{height}/g, config.height) | 
|                     .replace(/\{footer}/g, footer).replace(/\{data}/g, data).replace(/\{template}/g, cat); | 
|             } | 
|             return content; | 
|         }, | 
|         _previewDefault: function (file, previewId, isDisabled) { | 
|             var self = this, $preview = self.$preview, $previewLive = $preview.find('.file-live-thumbs'); | 
|             if (!self.showPreview) { | 
|                 return; | 
|             } | 
|             var fname = file ? file.name : '', ftype = file ? file.type : '', content, | 
|                 isError = isDisabled === true && !self.isUploadable, data = objUrl.createObjectURL(file); | 
|             self._clearDefaultPreview(); | 
|             content = self._generatePreviewTemplate('other', data, fname, ftype, previewId, isError, file.size); | 
|             if (!$previewLive.length) { | 
|                 $previewLive = $(document.createElement('div')).addClass('file-live-thumbs').appendTo($preview); | 
|             } | 
|             $previewLive.append("\n" + content); | 
|             if (isDisabled === true && self.isUploadable) { | 
|                 self._setThumbStatus($('#' + previewId), 'Error'); | 
|             } | 
|         }, | 
|         _previewFile: function (i, file, theFile, previewId, data) { | 
|             if (!this.showPreview) { | 
|                 return; | 
|             } | 
|             var self = this, cat = self._parseFileType(file), fname = file ? file.name : '', caption = self.slug(fname), | 
|                 types = self.allowedPreviewTypes, mimes = self.allowedPreviewMimeTypes, $preview = self.$preview, | 
|                 chkTypes = types && types.indexOf(cat) >= 0, $previewLive = $preview.find('.file-live-thumbs'), | 
|                 iData = (cat === 'text' || cat === 'html' || cat === 'image') ? theFile.target.result : data, content, | 
|                 chkMimes = mimes && mimes.indexOf(file.type) !== -1; | 
|             if (!$previewLive.length) { | 
|                 $previewLive = $(document.createElement('div')).addClass('file-live-thumbs').appendTo($preview); | 
|             } | 
|             /** @namespace window.DOMPurify */ | 
|             if (cat === 'html' && self.purifyHtml && window.DOMPurify) { | 
|                 iData = window.DOMPurify.sanitize(iData); | 
|             } | 
|             if (chkTypes || chkMimes) { | 
|                 content = self._generatePreviewTemplate(cat, iData, fname, file.type, previewId, false, file.size); | 
|                 self._clearDefaultPreview(); | 
|                 $previewLive.append("\n" + content); | 
|                 self._validateImage(i, previewId, caption, file.type); | 
|             } else { | 
|                 self._previewDefault(file, previewId); | 
|             } | 
|             self._initSortable(); | 
|         }, | 
|         _slugDefault: function (text) { | 
|             return isEmpty(text) ? '' : String(text).replace(/[\-\[\]\/\{}:;#%=\(\)\*\+\?\\\^\$\|<>&"']/g, '_'); | 
|         }, | 
|         _readFiles: function (files) { | 
|             this.reader = new FileReader(); | 
|             var self = this, $el = self.$element, $preview = self.$preview, reader = self.reader, | 
|                 $container = self.$previewContainer, $status = self.$previewStatus, msgLoading = self.msgLoading, | 
|                 msgProgress = self.msgProgress, previewInitId = self.previewInitId, numFiles = files.length, | 
|                 settings = self.fileTypeSettings, ctr = self.filestack.length, readFile, | 
|                 maxPreviewSize = self.maxFilePreviewSize && parseFloat(self.maxFilePreviewSize), | 
|                 canPreview = $preview.length && (!maxPreviewSize || isNaN(maxPreviewSize)), | 
|                 throwError = function (msg, file, previewId, index) { | 
|                     var p1 = $.extend(true, {}, self._getOutData({}, {}, files), {id: previewId, index: index}), | 
|                         p2 = {id: previewId, index: index, file: file, files: files}; | 
|                     self._previewDefault(file, previewId, true); | 
|                     if (self.isUploadable) { | 
|                         self.addToStack(undefined); | 
|                         setTimeout(function () { | 
|                             readFile(index + 1); | 
|                         }, 100); | 
|                     } | 
|                     self._initFileActions(); | 
|                     if (self.removeFromPreviewOnError) { | 
|                         $('#' + previewId).remove(); | 
|                     } | 
|                     return self.isUploadable ? self._showUploadError(msg, p1) : self._showError(msg, p2); | 
|                 }; | 
|   | 
|             self.loadedImages = []; | 
|             self.totalImagesCount = 0; | 
|   | 
|             $.each(files, function (key, file) { | 
|                 var func = self.fileTypeSettings.image || defaultFileTypeSettings.image; | 
|                 if (func && func(file.type)) { | 
|                     self.totalImagesCount++; | 
|                 } | 
|             }); | 
|             readFile = function (i) { | 
|                 if (isEmpty($el.attr('multiple'))) { | 
|                     numFiles = 1; | 
|                 } | 
|                 if (i >= numFiles) { | 
|                     if (self.isUploadable && self.filestack.length > 0) { | 
|                         self._raise('filebatchselected', [self.getFileStack()]); | 
|                     } else { | 
|                         self._raise('filebatchselected', [files]); | 
|                     } | 
|                     $container.removeClass('file-thumb-loading'); | 
|                     $status.html(''); | 
|                     return; | 
|                 } | 
|                 var node = ctr + i, previewId = previewInitId + "-" + node, isText, isImage, file = files[i], fSizeKB, | 
|                     caption = file.name ? self.slug(file.name) : '', fileSize = (file.size || 0) / 1000, checkFile, | 
|                     fileExtExpr = '', previewData = objUrl.createObjectURL(file), fileCount = 0, j, msg, typ, chk, | 
|                     fileTypes = self.allowedFileTypes, strTypes = isEmpty(fileTypes) ? '' : fileTypes.join(', '), | 
|                     fileExt = self.allowedFileExtensions, strExt = isEmpty(fileExt) ? '' : fileExt.join(', '); | 
|   | 
|                 if (caption === false) { | 
|                     readFile(i + 1); | 
|                     return; | 
|                 } | 
|                 if (caption.length === 0) { | 
|                     msg = self.msgInvalidFileName.replace('{name}', htmlEncode(file.name)); | 
|                     self.isError = throwError(msg, file, previewId, i); | 
|                     return; | 
|                 } | 
|                 if (!isEmpty(fileExt)) { | 
|                     fileExtExpr = new RegExp('\\.(' + fileExt.join('|') + ')$', 'i'); | 
|                 } | 
|                 fSizeKB = fileSize.toFixed(2); | 
|                 if (self.maxFileSize > 0 && fileSize > self.maxFileSize) { | 
|                     msg = self.msgSizeTooLarge.replace('{name}', caption).replace('{size}', fSizeKB) | 
|                         .replace('{maxSize}', self.maxFileSize); | 
|                     self.isError = throwError(msg, file, previewId, i); | 
|                     return; | 
|                 } | 
|                 if (self.minFileSize !== null && fileSize <= getNum(self.minFileSize)) { | 
|                     msg = self.msgSizeTooSmall.replace('{name}', caption).replace('{size}', fSizeKB) | 
|                         .replace('{minSize}', self.minFileSize); | 
|                     self.isError = throwError(msg, file, previewId, i); | 
|                     return; | 
|                 } | 
|                 if (!isEmpty(fileTypes) && isArray(fileTypes)) { | 
|                     for (j = 0; j < fileTypes.length; j += 1) { | 
|                         typ = fileTypes[j]; | 
|                         checkFile = settings[typ]; | 
|                         chk = (checkFile !== undefined && checkFile(file.type, caption)); | 
|                         fileCount += isEmpty(chk) ? 0 : chk.length; | 
|                     } | 
|                     if (fileCount === 0) { | 
|                         msg = self.msgInvalidFileType.replace('{name}', caption).replace('{types}', strTypes); | 
|                         self.isError = throwError(msg, file, previewId, i); | 
|                         return; | 
|                     } | 
|                 } | 
|                 if (fileCount === 0 && !isEmpty(fileExt) && isArray(fileExt) && !isEmpty(fileExtExpr)) { | 
|                     chk = compare(caption, fileExtExpr); | 
|                     fileCount += isEmpty(chk) ? 0 : chk.length; | 
|                     if (fileCount === 0) { | 
|                         msg = self.msgInvalidFileExtension.replace('{name}', caption).replace('{extensions}', strExt); | 
|                         self.isError = throwError(msg, file, previewId, i); | 
|                         return; | 
|                     } | 
|                 } | 
|                 if (!self.showPreview) { | 
|                     self.addToStack(file); | 
|                     setTimeout(function () { | 
|                         readFile(i + 1); | 
|                     }, 100); | 
|                     self._raise('fileloaded', [file, previewId, i, reader]); | 
|                     return; | 
|                 } | 
|                 if (!canPreview && fileSize > maxPreviewSize) { | 
|                     self.addToStack(file); | 
|                     $container.addClass('file-thumb-loading'); | 
|                     self._previewDefault(file, previewId); | 
|                     self._initFileActions(); | 
|                     self._updateFileDetails(numFiles); | 
|                     readFile(i + 1); | 
|                     return; | 
|                 } | 
|                 if ($preview.length && FileReader !== undefined) { | 
|                     $status.html(msgLoading.replace('{index}', i + 1).replace('{files}', numFiles)); | 
|                     $container.addClass('file-thumb-loading'); | 
|                     reader.onerror = function (evt) { | 
|                         self._errorHandler(evt, caption); | 
|                     }; | 
|                     reader.onload = function (theFile) { | 
|                         self._previewFile(i, file, theFile, previewId, previewData); | 
|                         self._initFileActions(); | 
|                     }; | 
|                     reader.onloadend = function () { | 
|                         msg = msgProgress.replace('{index}', i + 1).replace('{files}', numFiles) | 
|                             .replace('{percent}', 50).replace('{name}', caption); | 
|                         setTimeout(function () { | 
|                             $status.html(msg); | 
|                             self._updateFileDetails(numFiles); | 
|                             readFile(i + 1); | 
|                         }, 100); | 
|                         self._raise('fileloaded', [file, previewId, i, reader]); | 
|                     }; | 
|                     reader.onprogress = function (data) { | 
|                         if (data.lengthComputable) { | 
|                             var fact = (data.loaded / data.total) * 100, progress = Math.ceil(fact); | 
|                             msg = msgProgress.replace('{index}', i + 1).replace('{files}', numFiles) | 
|                                 .replace('{percent}', progress).replace('{name}', caption); | 
|                             setTimeout(function () { | 
|                                 $status.html(msg); | 
|                             }, 100); | 
|                         } | 
|                     }; | 
|                     isText = ifSet('text', settings, defaultFileTypeSettings.text); | 
|                     isImage = ifSet('image', settings, defaultFileTypeSettings.image); | 
|   | 
|                     if (isText(file.type, caption)) { | 
|                         reader.readAsText(file, self.textEncoding); | 
|                     } else { | 
|                         if (isImage(file.type, caption)) { | 
|                             reader.readAsDataURL(file); | 
|                         } else { | 
|                             reader.readAsArrayBuffer(file); | 
|                         } | 
|                     } | 
|                 } else { | 
|                     self._previewDefault(file, previewId); | 
|                     setTimeout(function () { | 
|                         readFile(i + 1); | 
|                         self._updateFileDetails(numFiles); | 
|                     }, 100); | 
|                     self._raise('fileloaded', [file, previewId, i, reader]); | 
|                 } | 
|                 self.addToStack(file); | 
|             }; | 
|   | 
|             readFile(0); | 
|             self._updateFileDetails(numFiles, false); | 
|         }, | 
|         _updateFileDetails: function (numFiles) { | 
|             var self = this, $el = self.$element, fileStack = self.getFileStack(), | 
|                 name = (isIE(9) && findFileName($el.val())) || | 
|                     ($el[0].files[0] && $el[0].files[0].name) || (fileStack.length && fileStack[0].name) || '', | 
|                 label = self.slug(name), n = self.isUploadable ? fileStack.length : numFiles, | 
|                 nFiles = previewCache.count(self.id) + n, log = n > 1 ? self._getMsgSelected(nFiles) : label; | 
|             if (self.isError) { | 
|                 self.$previewContainer.removeClass('file-thumb-loading'); | 
|                 self.$previewStatus.html(''); | 
|                 self.$captionContainer.find('.kv-caption-icon').hide(); | 
|             } else { | 
|                 self._showFileIcon(); | 
|             } | 
|             self._setCaption(log, self.isError); | 
|             self.$container.removeClass('file-input-new file-input-ajax-new'); | 
|             if (arguments.length === 1) { | 
|                 self._raise('fileselect', [numFiles, label]); | 
|             } | 
|             if (previewCache.count(self.id)) { | 
|                 self._initPreviewActions(); | 
|             } | 
|         }, | 
|         _setThumbStatus: function ($thumb, status) { | 
|             var self = this; | 
|             if (!self.showPreview) { | 
|                 return; | 
|             } | 
|             var icon = 'indicator' + status, msg = icon + 'Title', | 
|                 css = 'file-preview-' + status.toLowerCase(), | 
|                 $indicator = $thumb.find('.file-upload-indicator'), | 
|                 config = self.fileActionSettings; | 
|             $thumb.removeClass('file-preview-success file-preview-error file-preview-loading'); | 
|             if (status === 'Error') { | 
|                 $thumb.find('.kv-file-upload').attr('disabled', true); | 
|             } | 
|             if (status === 'Success') { | 
|                 $thumb.find('.file-drag-handle').remove(); | 
|                 $indicator.css('margin-left', 0); | 
|             } | 
|             $indicator.html(config[icon]); | 
|             $indicator.attr('title', config[msg]); | 
|             $thumb.addClass(css); | 
|         }, | 
|         _setProgressCancelled: function () { | 
|             var self = this; | 
|             self._setProgress(101, self.$progress, self.msgCancelled); | 
|         }, | 
|         _setProgress: function (p, $el, error) { | 
|             var self = this, pct = Math.min(p, 100), template = pct < 100 ? self.progressTemplate : | 
|                     (error ? self.progressErrorTemplate : (p <= 100 ? self.progressTemplate : self.progressCompleteTemplate)), | 
|                 pctLimit = self.progressUploadThreshold; | 
|             $el = $el || self.$progress; | 
|             if (!isEmpty(template)) { | 
|                 if (pctLimit && pct > pctLimit && p <= 100) { | 
|                     var out = template.replace('{percent}', pctLimit).replace('{percent}', pctLimit).replace('{percent}%', self.msgUploadThreshold); | 
|                     $el.html(out); | 
|                 } else { | 
|                     $el.html(template.replace(/\{percent}/g, pct)); | 
|                 } | 
|                 if (error) { | 
|                     $el.find('[role="progressbar"]').html(error); | 
|                 } | 
|             } | 
|         }, | 
|         _setFileDropZoneTitle: function () { | 
|             var self = this, $zone = self.$container.find('.file-drop-zone'), title = self.dropZoneTitle, strFiles; | 
|             if (self.isClickable) { | 
|                 strFiles = isEmpty(self.$element.attr('multiple')) ? self.fileSingle : self.filePlural; | 
|                 title += self.dropZoneClickTitle.replace('{files}', strFiles); | 
|             } | 
|             $zone.find('.' + self.dropZoneTitleClass).remove(); | 
|             if (!self.isUploadable || !self.showPreview || $zone.length === 0 || self.getFileStack().length > 0 || !self.dropZoneEnabled) { | 
|                 return; | 
|             } | 
|             if ($zone.find('.file-preview-frame').length === 0 && isEmpty(self.defaultPreviewContent)) { | 
|                 $zone.prepend('<div class="' + self.dropZoneTitleClass + '">' + title + '</div>'); | 
|             } | 
|             self.$container.removeClass('file-input-new'); | 
|             addCss(self.$container, 'file-input-ajax-new'); | 
|         }, | 
|         _setAsyncUploadStatus: function (previewId, pct, total) { | 
|             var self = this, sum = 0; | 
|             self._setProgress(pct, $('#' + previewId).find('.file-thumb-progress')); | 
|             self.uploadStatus[previewId] = pct; | 
|             $.each(self.uploadStatus, function (key, value) { | 
|                 sum += value; | 
|             }); | 
|             self._setProgress(Math.floor(sum / total)); | 
|   | 
|         }, | 
|         _validateMinCount: function () { | 
|             var self = this, len = self.isUploadable ? self.getFileStack().length : self.$element.get(0).files.length; | 
|             if (self.validateInitialCount && self.minFileCount > 0 && self._getFileCount(len - 1) < self.minFileCount) { | 
|                 self._noFilesError({}); | 
|                 return false; | 
|             } | 
|             return true; | 
|         }, | 
|         _getFileCount: function (fileCount) { | 
|             var self = this, addCount = 0; | 
|             if (self.validateInitialCount && !self.overwriteInitial) { | 
|                 addCount = previewCache.count(self.id); | 
|                 fileCount += addCount; | 
|             } | 
|             return fileCount; | 
|         }, | 
|         _getFileName: function (file) { | 
|             return file && file.name ? this.slug(file.name) : undefined; | 
|         }, | 
|         _getFileNames: function (skipNull) { | 
|             var self = this; | 
|             return self.filenames.filter(function (n) { | 
|                 return (skipNull ? n !== undefined : n !== undefined && n !== null); | 
|             }); | 
|         }, | 
|         _setPreviewError: function ($thumb, i, val) { | 
|             var self = this; | 
|             if (i !== undefined) { | 
|                 self.updateStack(i, val); | 
|             } | 
|             if (self.removeFromPreviewOnError) { | 
|                 $thumb.remove(); | 
|             } else { | 
|                 self._setThumbStatus($thumb, 'Error'); | 
|             } | 
|         }, | 
|         _checkDimensions: function (i, chk, $img, $thumb, fname, type, params) { | 
|             var self = this, msg, dim, tag = chk === 'Small' ? 'min' : 'max', limit = self[tag + 'Image' + type], | 
|                 $imgEl, isValid; | 
|             if (isEmpty(limit) || !$img.length) { | 
|                 return; | 
|             } | 
|             $imgEl = $img[0]; | 
|             dim = (type === 'Width') ? $imgEl.naturalWidth || $imgEl.width : $imgEl.naturalHeight || $imgEl.height; | 
|             isValid = chk === 'Small' ? dim >= limit : dim <= limit; | 
|             if (isValid) { | 
|                 return; | 
|             } | 
|             msg = self['msgImage' + type + chk].replace('{name}', fname).replace('{size}', limit); | 
|             self._showUploadError(msg, params); | 
|             self._setPreviewError($thumb, i, null); | 
|         }, | 
|         _validateImage: function (i, previewId, fname, ftype) { | 
|             var self = this, $preview = self.$preview, params, w1, w2, | 
|                 $thumb = $preview.find("#" + previewId), $img = $thumb.find('img'); | 
|             fname = fname || 'Untitled'; | 
|             if (!$img.length) { | 
|                 return; | 
|             } | 
|             handler($img, 'load', function () { | 
|                 w1 = $thumb.width(); | 
|                 w2 = $preview.width(); | 
|                 if (w1 > w2) { | 
|                     $img.css('width', '100%'); | 
|                     $thumb.css('width', '97%'); | 
|                 } | 
|                 params = {ind: i, id: previewId}; | 
|                 self._checkDimensions(i, 'Small', $img, $thumb, fname, 'Width', params); | 
|                 self._checkDimensions(i, 'Small', $img, $thumb, fname, 'Height', params); | 
|                 if (!self.resizeImage) { | 
|                     self._checkDimensions(i, 'Large', $img, $thumb, fname, 'Width', params); | 
|                     self._checkDimensions(i, 'Large', $img, $thumb, fname, 'Height', params); | 
|                 } | 
|                 self._raise('fileimageloaded', [previewId]); | 
|                 self.loadedImages.push({ind: i, img: $img, thumb: $thumb, pid: previewId, typ: ftype}); | 
|                 self._validateAllImages(); | 
|                 objUrl.revokeObjectURL($img.attr('src')); | 
|             }); | 
|         }, | 
|         _validateAllImages: function () { | 
|             var self = this, i, config, $img, $thumb, pid, ind, params = {}, errFunc; | 
|             if (self.loadedImages.length !== self.totalImagesCount) { | 
|                 return; | 
|             } | 
|             self._raise('fileimagesloaded'); | 
|             if (!self.resizeImage) { | 
|                 return; | 
|             } | 
|             errFunc = self.isUploadable ? self._showUploadError : self._showError; | 
|             var counter = {val: 0}; | 
|             for (i = 0; i < self.loadedImages.length; i++) { | 
|                 config = self.loadedImages[i]; | 
|                 $img = config.img; | 
|                 $thumb = config.thumb; | 
|                 pid = config.pid; | 
|                 ind = config.ind; | 
|                 params = {id: pid, 'index': ind}; | 
|                 if (!self._getResizedImage($img[0], config.typ, pid, ind, counter, self.loadedImages.length)) { | 
|                     errFunc(self.msgImageResizeError, params, 'fileimageresizeerror'); | 
|                     self._setPreviewError($thumb, ind); | 
|                 } | 
|             } | 
|         }, | 
|         _getResizedImage: function (image, type, pid, ind, counter, num_imgs) { | 
|             var self = this, width = image.naturalWidth, height = image.naturalHeight, ratio = 1, | 
|                 maxWidth = self.maxImageWidth || width, maxHeight = self.maxImageHeight || height, | 
|                 isValidImage = (width && height), chkWidth, chkHeight, | 
|                 canvas = self.imageCanvas, context = self.imageCanvasContext; | 
|             if (!isValidImage) { | 
|                 counter.val++; | 
|                 if (counter.val === num_imgs) { | 
|                     self._raise('fileimagesresized'); | 
|                 } | 
|                 return false; | 
|             } | 
|             if (width === maxWidth && height === maxHeight) { | 
|                 self._raise('fileimageresized', [pid, ind]); | 
|                 counter.val++; | 
|                 if (counter.val === num_imgs) { | 
|                     self._raise('fileimagesresized'); | 
|                 } | 
|                 return true; | 
|             } | 
|             type = type || self.resizeDefaultImageType; | 
|             chkWidth = width > maxWidth; | 
|             chkHeight = height > maxHeight; | 
|             if (self.resizePreference === 'width') { | 
|                 ratio = chkWidth ? maxWidth / width : (chkHeight ? maxHeight / height : 1); | 
|             } else { | 
|                 ratio = chkHeight ? maxHeight / height : (chkWidth ? maxWidth / width : 1); | 
|             } | 
|             self._resetCanvas(); | 
|             width *= ratio; | 
|             height *= ratio; | 
|             canvas.width = width; | 
|             canvas.height = height; | 
|             try { | 
|                 context.drawImage(image, 0, 0, width, height); | 
|                 canvas.toBlob(function (blob) { | 
|                     self.filestack[ind] = blob; | 
|                     self._raise('fileimageresized', [pid, ind]); | 
|                     counter.val++; | 
|                     if (counter.val === num_imgs) { | 
|                         self._raise('fileimagesresized', [undefined, undefined]); | 
|                     } | 
|                 }, type, self.resizeQuality); | 
|                 return true; | 
|             } | 
|             catch (err) { | 
|                 counter.val++; | 
|                 if (counter.val === num_imgs) { | 
|                     self._raise('fileimagesresized', [undefined, undefined]); | 
|                 } | 
|                 return false; | 
|             } | 
|         }, | 
|         _initBrowse: function ($container) { | 
|             var self = this; | 
|             if (self.showBrowse) { | 
|                 self.$btnFile = $container.find('.btn-file'); | 
|                 self.$btnFile.append(self.$element); | 
|             } else { | 
|                 self.$element.hide(); | 
|             } | 
|         }, | 
|         _initCaption: function () { | 
|             var self = this, cap = self.initialCaption || ''; | 
|             if (self.overwriteInitial || isEmpty(cap)) { | 
|                 self.$caption.html(''); | 
|                 return false; | 
|             } | 
|             self._setCaption(cap); | 
|             return true; | 
|         }, | 
|         _setCaption: function (content, isError) { | 
|             var self = this, title, out, n, cap, stack = self.getFileStack(); | 
|             if (!self.$caption.length) { | 
|                 return; | 
|             } | 
|             if (isError) { | 
|                 title = $('<div>' + self.msgValidationError + '</div>').text(); | 
|                 n = stack.length; | 
|                 if (n) { | 
|                     cap = n === 1 && stack[0] ? self._getFileNames()[0] : self._getMsgSelected(n); | 
|                 } else { | 
|                     cap = self._getMsgSelected(self.msgNo); | 
|                 } | 
|                 out = '<span class="' + self.msgValidationErrorClass + '">' + self.msgValidationErrorIcon + | 
|                     (isEmpty(content) ? cap : content) + '</span>'; | 
|             } else { | 
|                 if (isEmpty(content)) { | 
|                     return; | 
|                 } | 
|                 title = $('<div>' + content + '</div>').text(); | 
|                 out = self._getLayoutTemplate('fileIcon') + title; | 
|             } | 
|             self.$caption.html(out); | 
|             self.$caption.attr('title', title); | 
|             self.$captionContainer.find('.file-caption-ellipsis').attr('title', title); | 
|         }, | 
|         _createContainer: function () { | 
|             var self = this, $container = $(document.createElement("div")) | 
|                 .attr({"class": 'file-input file-input-new'}) | 
|                 .html(self._renderMain()); | 
|             self.$element.before($container); | 
|             self._initBrowse($container); | 
|             if (self.theme) { | 
|                 $container.addClass('theme-' + self.theme); | 
|             } | 
|             return $container; | 
|         }, | 
|         _refreshContainer: function () { | 
|             var self = this, $container = self.$container; | 
|             $container.before(self.$element); | 
|             $container.html(self._renderMain()); | 
|             self._initBrowse($container); | 
|         }, | 
|         _renderMain: function () { | 
|             var self = this, dropCss = (self.isUploadable && self.dropZoneEnabled) ? ' file-drop-zone' : 'file-drop-disabled', | 
|                 close = !self.showClose ? '' : self._getLayoutTemplate('close'), | 
|                 preview = !self.showPreview ? '' : self._getLayoutTemplate('preview') | 
|                     .replace(/\{class}/g, self.previewClass) | 
|                     .replace(/\{dropClass}/g, dropCss), | 
|                 css = self.isDisabled ? self.captionClass + ' file-caption-disabled' : self.captionClass, | 
|                 caption = self.captionTemplate.replace(/\{class}/g, css + ' kv-fileinput-caption'); | 
|             return self.mainTemplate.replace(/\{class}/g, self.mainClass + | 
|                 (!self.showBrowse && self.showCaption ? ' no-browse' : '')) | 
|                 .replace(/\{preview}/g, preview) | 
|                 .replace(/\{close}/g, close) | 
|                 .replace(/\{caption}/g, caption) | 
|                 .replace(/\{upload}/g, self._renderButton('upload')) | 
|                 .replace(/\{remove}/g, self._renderButton('remove')) | 
|                 .replace(/\{cancel}/g, self._renderButton('cancel')) | 
|                 .replace(/\{browse}/g, self._renderButton('browse')); | 
|         }, | 
|         _renderButton: function (type) { | 
|             var self = this, tmplt = self._getLayoutTemplate('btnDefault'), css = self[type + 'Class'], | 
|                 title = self[type + 'Title'], icon = self[type + 'Icon'], label = self[type + 'Label'], | 
|                 status = self.isDisabled ? ' disabled' : '', btnType = 'button'; | 
|             switch (type) { | 
|                 case 'remove': | 
|                     if (!self.showRemove) { | 
|                         return ''; | 
|                     } | 
|                     break; | 
|                 case 'cancel': | 
|                     if (!self.showCancel) { | 
|                         return ''; | 
|                     } | 
|                     css += ' hide'; | 
|                     break; | 
|                 case 'upload': | 
|                     if (!self.showUpload) { | 
|                         return ''; | 
|                     } | 
|                     if (self.isUploadable && !self.isDisabled) { | 
|                         tmplt = self._getLayoutTemplate('btnLink').replace('{href}', self.uploadUrl); | 
|                     } else { | 
|                         btnType = 'submit'; | 
|                     } | 
|                     break; | 
|                 case 'browse': | 
|                     if (!self.showBrowse) { | 
|                         return ''; | 
|                     } | 
|                     tmplt = self._getLayoutTemplate('btnBrowse'); | 
|                     break; | 
|                 default: | 
|                     return ''; | 
|             } | 
|   | 
|             css += type === 'browse' ? ' btn-file' : ' fileinput-' + type + ' fileinput-' + type + '-button'; | 
|             if (!isEmpty(label)) { | 
|                 label = ' <span class="' + self.buttonLabelClass + '">' + label + '</span>'; | 
|             } | 
|             return tmplt.replace('{type}', btnType).replace('{css}', css).replace('{title}', title) | 
|                 .replace('{status}', status).replace('{icon}', icon).replace('{label}', label); | 
|         }, | 
|         _renderThumbProgress: function () { | 
|             return '<div class="file-thumb-progress hide">' + this.progressTemplate.replace(/\{percent}/g, | 
|                     '0') + '</div>'; | 
|         }, | 
|         _renderFileFooter: function (caption, size, width, isError) { | 
|             var self = this, config = self.fileActionSettings, rem = config.showRemove, drg = config.showDrag, | 
|                 upl = config.showUpload, zoom = config.showZoom, out, template = self._getLayoutTemplate('footer'), | 
|                 indicator = isError ? config.indicatorError : config.indicatorNew, | 
|                 title = isError ? config.indicatorErrorTitle : config.indicatorNewTitle; | 
|             size = self._getSize(size); | 
|             if (self.isUploadable) { | 
|                 out = template.replace(/\{actions}/g, self._renderFileActions(upl, rem, zoom, drg, false, false, false)) | 
|                     .replace(/\{caption}/g, caption).replace(/\{size}/g, size).replace(/\{width}/g, width) | 
|                     .replace(/\{progress}/g, self._renderThumbProgress()).replace(/\{indicator}/g, indicator) | 
|                     .replace(/\{indicatorTitle}/g, title); | 
|             } else { | 
|                 out = template.replace(/\{actions}/g, | 
|                     self._renderFileActions(false, false, zoom, drg, false, false, false)) | 
|                     .replace(/\{caption}/g, caption).replace(/\{size}/g, size).replace(/\{width}/g, width) | 
|                     .replace(/\{progress}/g, '').replace(/\{indicator}/g, indicator) | 
|                     .replace(/\{indicatorTitle}/g, title); | 
|             } | 
|             out = replaceTags(out, self.previewThumbTags); | 
|             return out; | 
|         }, | 
|         _renderFileActions: function (showUpload, showDelete, showZoom, showDrag, disabled, url, key, isInit) { | 
|             if (!showUpload && !showDelete && !showZoom && !showDrag) { | 
|                 return ''; | 
|             } | 
|             var self = this, | 
|                 vUrl = url === false ? '' : ' data-url="' + url + '"', | 
|                 vKey = key === false ? '' : ' data-key="' + key + '"', | 
|                 btnDelete = '', btnUpload = '', btnZoom = '', btnDrag = '', css, | 
|                 template = self._getLayoutTemplate('actions'), config = self.fileActionSettings, | 
|                 otherButtons = self.otherActionButtons.replace(/\{dataKey}/g, vKey), | 
|                 removeClass = disabled ? config.removeClass + ' disabled' : config.removeClass; | 
|             if (showDelete) { | 
|                 btnDelete = self._getLayoutTemplate('actionDelete') | 
|                     .replace(/\{removeClass}/g, removeClass) | 
|                     .replace(/\{removeIcon}/g, config.removeIcon) | 
|                     .replace(/\{removeTitle}/g, config.removeTitle) | 
|                     .replace(/\{dataUrl}/g, vUrl) | 
|                     .replace(/\{dataKey}/g, vKey); | 
|             } | 
|             if (showUpload) { | 
|                 btnUpload = self._getLayoutTemplate('actionUpload') | 
|                     .replace(/\{uploadClass}/g, config.uploadClass) | 
|                     .replace(/\{uploadIcon}/g, config.uploadIcon) | 
|                     .replace(/\{uploadTitle}/g, config.uploadTitle); | 
|             } | 
|             if (showZoom) { | 
|                 btnZoom = self._getLayoutTemplate('actionZoom') | 
|                     .replace(/\{zoomClass}/g, config.zoomClass) | 
|                     .replace(/\{zoomIcon}/g, config.zoomIcon) | 
|                     .replace(/\{zoomTitle}/g, config.zoomTitle); | 
|             } | 
|             if (showDrag && isInit) { | 
|                 css = 'drag-handle-init ' + config.dragClass; | 
|                 btnDrag = self._getLayoutTemplate('actionDrag').replace(/\{dragClass}/g, css) | 
|                     .replace(/\{dragTitle}/g, config.dragTitle) | 
|                     .replace(/\{dragIcon}/g, config.dragIcon); | 
|             } | 
|             return template.replace(/\{delete}/g, btnDelete) | 
|                 .replace(/\{upload}/g, btnUpload) | 
|                 .replace(/\{zoom}/g, btnZoom) | 
|                 .replace(/\{drag}/g, btnDrag) | 
|                 .replace(/\{other}/g, otherButtons); | 
|         }, | 
|         _browse: function (e) { | 
|             var self = this; | 
|             self._raise('filebrowse'); | 
|             if (e && e.isDefaultPrevented()) { | 
|                 return; | 
|             } | 
|             if (self.isError && !self.isUploadable) { | 
|                 self.clear(); | 
|             } | 
|             self.$captionContainer.focus(); | 
|         }, | 
|         _change: function (e) { | 
|             var self = this, $el = self.$element; | 
|             if (!self.isUploadable && isEmpty($el.val()) && self.fileInputCleared) { // IE 11 fix | 
|                 self.fileInputCleared = false; | 
|                 return; | 
|             } | 
|             self.fileInputCleared = false; | 
|             var tfiles, msg, total, isDragDrop = arguments.length > 1, isAjaxUpload = self.isUploadable, i = 0, f, n, len, | 
|                 files = isDragDrop ? e.originalEvent.dataTransfer.files : $el.get(0).files, ctr = self.filestack.length, | 
|                 isSingleUpload = isEmpty($el.attr('multiple')), flagSingle = (isSingleUpload && ctr > 0), folders = 0, | 
|                 throwError = function (mesg, file, previewId, index) { | 
|                     var p1 = $.extend(true, {}, self._getOutData({}, {}, files), {id: previewId, index: index}), | 
|                         p2 = {id: previewId, index: index, file: file, files: files}; | 
|                     return self.isUploadable ? self._showUploadError(mesg, p1) : self._showError(mesg, p2); | 
|                 }; | 
|             self.reader = null; | 
|             self._resetUpload(); | 
|             self._hideFileIcon(); | 
|             if (self.isUploadable) { | 
|                 self.$container.find('.file-drop-zone .' + self.dropZoneTitleClass).remove(); | 
|             } | 
|             if (isDragDrop) { | 
|                 tfiles = []; | 
|                 while (files[i]) { | 
|                     f = files[i]; | 
|                     if (!f.type && f.size % 4096 === 0) { | 
|                         folders++; | 
|                     } else { | 
|                         tfiles.push(f); | 
|                     } | 
|                     i++; | 
|                 } | 
|             } else { | 
|                 if (e.target.files === undefined) { | 
|                     tfiles = e.target && e.target.value ? [ | 
|                         {name: e.target.value.replace(/^.+\\/, '')} | 
|                     ] : []; | 
|                 } else { | 
|                     tfiles = e.target.files; | 
|                 } | 
|             } | 
|             if (isEmpty(tfiles) || tfiles.length === 0) { | 
|                 if (!isAjaxUpload) { | 
|                     self.clear(); | 
|                 } | 
|                 self._showFolderError(folders); | 
|                 self._raise('fileselectnone'); | 
|                 return; | 
|             } | 
|             self._resetErrors(); | 
|             len = tfiles.length; | 
|             total = self._getFileCount(self.isUploadable ? (self.getFileStack().length + len) : len); | 
|             if (self.maxFileCount > 0 && total > self.maxFileCount) { | 
|                 if (!self.autoReplace || len > self.maxFileCount) { | 
|                     n = (self.autoReplace && len > self.maxFileCount) ? len : total; | 
|                     msg = self.msgFilesTooMany.replace('{m}', self.maxFileCount).replace('{n}', n); | 
|                     self.isError = throwError(msg, null, null, null); | 
|                     self.$captionContainer.find('.kv-caption-icon').hide(); | 
|                     self._setCaption('', true); | 
|                     self.$container.removeClass('file-input-new file-input-ajax-new'); | 
|                     return; | 
|                 } | 
|                 if (total > self.maxFileCount) { | 
|                     self._resetPreviewThumbs(isAjaxUpload); | 
|                 } | 
|             } else { | 
|                 if (!isAjaxUpload || flagSingle) { | 
|                     self._resetPreviewThumbs(false); | 
|                     if (flagSingle) { | 
|                         self.clearStack(); | 
|                     } | 
|                 } else { | 
|                     if (isAjaxUpload && ctr === 0 && (!previewCache.count(self.id) || self.overwriteInitial)) { | 
|                         self._resetPreviewThumbs(true); | 
|                     } | 
|                 } | 
|             } | 
|             if (self.isPreviewable) { | 
|                 self._readFiles(tfiles); | 
|             } else { | 
|                 self._updateFileDetails(1); | 
|             } | 
|             self._showFolderError(folders); | 
|         }, | 
|         _abort: function (params) { | 
|             var self = this, data; | 
|             if (self.ajaxAborted && typeof self.ajaxAborted === "object" && self.ajaxAborted.message !== undefined) { | 
|                 data = $.extend(true, {}, self._getOutData(), params); | 
|                 data.abortData = self.ajaxAborted.data || {}; | 
|                 data.abortMessage = self.ajaxAborted.message; | 
|                 self.cancel(); | 
|                 self._setProgress(101, self.$progress, self.msgCancelled); | 
|                 self._showUploadError(self.ajaxAborted.message, data, 'filecustomerror'); | 
|                 return true; | 
|             } | 
|             return false; | 
|         }, | 
|         _resetFileStack: function () { | 
|             var self = this, i = 0, newstack = [], newnames = []; | 
|             self._getThumbs().each(function () { | 
|                 var $thumb = $(this), ind = $thumb.attr('data-fileindex'), | 
|                     file = self.filestack[ind]; | 
|                 if (ind === -1) { | 
|                     return; | 
|                 } | 
|                 if (file !== undefined) { | 
|                     newstack[i] = file; | 
|                     newnames[i] = self._getFileName(file); | 
|                     $thumb.attr({ | 
|                         'id': self.previewInitId + '-' + i, | 
|                         'data-fileindex': i | 
|                     }); | 
|                     i++; | 
|                 } else { | 
|                     $thumb.attr({ | 
|                         'id': 'uploaded-' + uniqId(), | 
|                         'data-fileindex': '-1' | 
|                     }); | 
|                 } | 
|             }); | 
|             self.filestack = newstack; | 
|             self.filenames = newnames; | 
|         }, | 
|         clearStack: function () { | 
|             var self = this; | 
|             self.filestack = []; | 
|             self.filenames = []; | 
|             return self.$element; | 
|         }, | 
|         updateStack: function (i, file) { | 
|             var self = this; | 
|             self.filestack[i] = file; | 
|             self.filenames[i] = self._getFileName(file); | 
|             return self.$element; | 
|         }, | 
|         addToStack: function (file) { | 
|             var self = this; | 
|             self.filestack.push(file); | 
|             self.filenames.push(self._getFileName(file)); | 
|             return self.$element; | 
|         }, | 
|         getFileStack: function (skipNull) { | 
|             var self = this; | 
|             return self.filestack.filter(function (n) { | 
|                 return (skipNull ? n !== undefined : n !== undefined && n !== null); | 
|             }); | 
|         }, | 
|         getFilesCount: function () { | 
|             var self = this, len = self.isUploadable ? self.getFileStack().length : self.$element.get(0).files.length; | 
|             return self._getFileCount(len); | 
|         }, | 
|         lock: function () { | 
|             var self = this; | 
|             self._resetErrors(); | 
|             self.disable(); | 
|             if (self.showRemove) { | 
|                 addCss(self.$container.find('.fileinput-remove'), 'hide'); | 
|             } | 
|             if (self.showCancel) { | 
|                 self.$container.find('.fileinput-cancel').removeClass('hide'); | 
|             } | 
|             self._raise('filelock', [self.filestack, self._getExtraData()]); | 
|             return self.$element; | 
|         }, | 
|         unlock: function (reset) { | 
|             var self = this; | 
|             if (reset === undefined) { | 
|                 reset = true; | 
|             } | 
|             self.enable(); | 
|             if (self.showCancel) { | 
|                 addCss(self.$container.find('.fileinput-cancel'), 'hide'); | 
|             } | 
|             if (self.showRemove) { | 
|                 self.$container.find('.fileinput-remove').removeClass('hide'); | 
|             } | 
|             if (reset) { | 
|                 self._resetFileStack(); | 
|             } | 
|             self._raise('fileunlock', [self.filestack, self._getExtraData()]); | 
|             return self.$element; | 
|         }, | 
|         cancel: function () { | 
|             var self = this, xhr = self.ajaxRequests, len = xhr.length, i; | 
|             if (len > 0) { | 
|                 for (i = 0; i < len; i += 1) { | 
|                     self.cancelling = true; | 
|                     xhr[i].abort(); | 
|                 } | 
|             } | 
|             self._setProgressCancelled(); | 
|             self._getThumbs().each(function () { | 
|                 var $thumb = $(this), ind = $thumb.attr('data-fileindex'); | 
|                 $thumb.removeClass('file-uploading'); | 
|                 if (self.filestack[ind] !== undefined) { | 
|                     $thumb.find('.kv-file-upload').removeClass('disabled').removeAttr('disabled'); | 
|                     $thumb.find('.kv-file-remove').removeClass('disabled').removeAttr('disabled'); | 
|                 } | 
|                 self.unlock(); | 
|             }); | 
|             return self.$element; | 
|         }, | 
|         clear: function () { | 
|             var self = this, cap; | 
|             self.$btnUpload.removeAttr('disabled'); | 
|             self._getThumbs().find('video,audio,img').each(function () { | 
|                 cleanMemory($(this)); | 
|             }); | 
|             self._resetUpload(); | 
|             self.clearStack(); | 
|             self._clearFileInput(); | 
|             self._resetErrors(true); | 
|             self._raise('fileclear'); | 
|             if (self._hasInitialPreview()) { | 
|                 self._showFileIcon(); | 
|                 self._resetPreview(); | 
|                 self._initPreviewActions(); | 
|                 self.$container.removeClass('file-input-new'); | 
|             } else { | 
|                 self._getThumbs().each(function () { | 
|                     self._clearObjects($(this)); | 
|                 }); | 
|                 if (self.isUploadable) { | 
|                     previewCache.data[self.id] = {}; | 
|                 } | 
|                 self.$preview.html(''); | 
|                 cap = (!self.overwriteInitial && self.initialCaption.length > 0) ? self.initialCaption : ''; | 
|                 self.$caption.html(cap); | 
|                 self.$caption.attr('title', ''); | 
|                 addCss(self.$container, 'file-input-new'); | 
|                 self._validateDefaultPreview(); | 
|             } | 
|             if (self.$container.find('.file-preview-frame').length === 0) { | 
|                 if (!self._initCaption()) { | 
|                     self.$captionContainer.find('.kv-caption-icon').hide(); | 
|                 } | 
|             } | 
|             self._hideFileIcon(); | 
|             self._raise('filecleared'); | 
|             self.$captionContainer.focus(); | 
|             self._setFileDropZoneTitle(); | 
|             return self.$element; | 
|         }, | 
|         reset: function () { | 
|             var self = this; | 
|             self._resetPreview(); | 
|             self.$container.find('.fileinput-filename').text(''); | 
|             self._raise('filereset'); | 
|             addCss(self.$container, 'file-input-new'); | 
|             if (self.$preview.find('.file-preview-frame').length || self.isUploadable && self.dropZoneEnabled) { | 
|                 self.$container.removeClass('file-input-new'); | 
|             } | 
|             self._setFileDropZoneTitle(); | 
|             self.clearStack(); | 
|             self.formdata = {}; | 
|             return self.$element; | 
|         }, | 
|         disable: function () { | 
|             var self = this; | 
|             self.isDisabled = true; | 
|             self._raise('filedisabled'); | 
|             self.$element.attr('disabled', 'disabled'); | 
|             self.$container.find(".kv-fileinput-caption").addClass("file-caption-disabled"); | 
|             self.$container.find(".btn-file, .fileinput-remove, .fileinput-upload, .file-preview-frame button").attr( | 
|                 "disabled", | 
|                 true); | 
|             self._initDragDrop(); | 
|             return self.$element; | 
|         }, | 
|         enable: function () { | 
|             var self = this; | 
|             self.isDisabled = false; | 
|             self._raise('fileenabled'); | 
|             self.$element.removeAttr('disabled'); | 
|             self.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled"); | 
|             self.$container.find( | 
|                 ".btn-file, .fileinput-remove, .fileinput-upload, .file-preview-frame button").removeAttr("disabled"); | 
|             self._initDragDrop(); | 
|             return self.$element; | 
|         }, | 
|         upload: function () { | 
|             var self = this, totLen = self.getFileStack().length, params = {}, | 
|                 i, outData, len, hasExtraData = !$.isEmptyObject(self._getExtraData()); | 
|             if (self.minFileCount > 0 && self._getFileCount(totLen) < self.minFileCount) { | 
|                 self._noFilesError(params); | 
|                 return; | 
|             } | 
|             if (!self.isUploadable || self.isDisabled || (totLen === 0 && !hasExtraData)) { | 
|                 return; | 
|             } | 
|             self._resetUpload(); | 
|             self.$progress.removeClass('hide'); | 
|             self.uploadCount = 0; | 
|             self.uploadStatus = {}; | 
|             self.uploadLog = []; | 
|             self.lock(); | 
|             self._setProgress(2); | 
|             if (totLen === 0 && hasExtraData) { | 
|                 self._uploadExtraOnly(); | 
|                 return; | 
|             } | 
|             len = self.filestack.length; | 
|             self.hasInitData = false; | 
|             if (self.uploadAsync) { | 
|                 outData = self._getOutData(); | 
|                 self._raise('filebatchpreupload', [outData]); | 
|                 self.fileBatchCompleted = false; | 
|                 self.uploadCache = {content: [], config: [], tags: [], append: true}; | 
|                 self.uploadAsyncCount = self.getFileStack().length; | 
|                 for (i = 0; i < len; i++) { | 
|                     self.uploadCache.content[i] = null; | 
|                     self.uploadCache.config[i] = null; | 
|                     self.uploadCache.tags[i] = null; | 
|                 } | 
|                 for (i = 0; i < len; i++) { | 
|                     if (self.filestack[i] !== undefined) { | 
|                         self._uploadSingle(i, self.filestack, true); | 
|                     } | 
|                 } | 
|                 return; | 
|             } | 
|             self._uploadBatch(); | 
|             return self.$element; | 
|         }, | 
|         destroy: function () { | 
|             var self = this, $cont = self.$container; | 
|             $cont.find('.file-drop-zone').off(); | 
|             self.$element.insertBefore($cont).off(NAMESPACE).removeData(); | 
|             $cont.off().remove(); | 
|             return self.$element; | 
|         }, | 
|         refresh: function (options) { | 
|             var self = this, $el = self.$element; | 
|             options = options ? $.extend(true, {}, self.options, options) : self.options; | 
|             self.destroy(); | 
|             $el.fileinput(options); | 
|             if ($el.val()) { | 
|                 $el.trigger('change.fileinput'); | 
|             } | 
|             return $el; | 
|         } | 
|     }; | 
|   | 
|     $.fn.fileinput = function (option) { | 
|         if (!hasFileAPISupport() && !isIE(9)) { | 
|             return; | 
|         } | 
|         var args = Array.apply(null, arguments), retvals = []; | 
|         args.shift(); | 
|         this.each(function () { | 
|             var self = $(this), data = self.data('fileinput'), options = typeof option === 'object' && option, | 
|                 theme = options.theme || self.data('theme'), l = {}, t = {}, | 
|                 lang = options.language || self.data('language') || 'en', opts; | 
|             if (!data) { | 
|                 if (theme) { | 
|                     t = $.fn.fileinputThemes[theme] || {}; | 
|                 } | 
|                 if (lang !== 'en' && !isEmpty($.fn.fileinputLocales[lang])) { | 
|                     l = $.fn.fileinputLocales[lang] || {}; | 
|                 } | 
|                 opts = $.extend(true, {}, $.fn.fileinput.defaults, t, $.fn.fileinputLocales.en, l, options, | 
|                     self.data()); | 
|                 data = new FileInput(this, opts); | 
|                 self.data('fileinput', data); | 
|             } | 
|   | 
|             if (typeof option === 'string') { | 
|                 retvals.push(data[option].apply(data, args)); | 
|             } | 
|         }); | 
|         switch (retvals.length) { | 
|             case 0: | 
|                 return this; | 
|             case 1: | 
|                 return retvals[0]; | 
|             default: | 
|                 return retvals; | 
|         } | 
|     }; | 
|   | 
|     $.fn.fileinput.defaults = { | 
|         language: 'en', | 
|         showCaption: true, | 
|         showBrowse: true, | 
|         showPreview: true, | 
|         showRemove: true, | 
|         showUpload: true, | 
|         showCancel: true, | 
|         showClose: true, | 
|         showUploadedThumbs: true, | 
|         browseOnZoneClick: false, | 
|         autoReplace: false, | 
|         previewClass: '', | 
|         captionClass: '', | 
|         mainClass: 'file-caption-main', | 
|         mainTemplate: null, | 
|         purifyHtml: true, | 
|         fileSizeGetter: null, | 
|         initialCaption: '', | 
|         initialPreview: [], | 
|         initialPreviewDelimiter: '*$$*', | 
|         initialPreviewAsData: false, | 
|         initialPreviewFileType: 'image', | 
|         initialPreviewConfig: [], | 
|         initialPreviewThumbTags: [], | 
|         previewThumbTags: {}, | 
|         initialPreviewShowDelete: true, | 
|         removeFromPreviewOnError: false, | 
|         deleteUrl: '', | 
|         deleteExtraData: {}, | 
|         overwriteInitial: true, | 
|         layoutTemplates: defaultLayoutTemplates, | 
|         previewTemplates: defaultPreviewTemplates, | 
|         previewZoomSettings: defaultPreviewZoomSettings, | 
|         previewZoomButtonIcons: { | 
|             prev: '<i class="glyphicon glyphicon-triangle-left"></i>', | 
|             next: '<i class="glyphicon glyphicon-triangle-right"></i>', | 
|             toggleheader: '<i class="glyphicon glyphicon-resize-vertical"></i>', | 
|             fullscreen: '<i class="glyphicon glyphicon-fullscreen"></i>', | 
|             borderless: '<i class="glyphicon glyphicon-resize-full"></i>', | 
|             close: '<i class="glyphicon glyphicon-remove"></i>' | 
|         }, | 
|         previewZoomButtonClasses: { | 
|             prev: 'btn btn-navigate', | 
|             next: 'btn btn-navigate', | 
|             toggleheader: 'btn btn-default btn-header-toggle', | 
|             fullscreen: 'btn btn-default', | 
|             borderless: 'btn btn-default', | 
|             close: 'btn btn-default' | 
|         }, | 
|         allowedPreviewTypes: defaultPreviewTypes, | 
|         allowedPreviewMimeTypes: null, | 
|         allowedFileTypes: null, | 
|         allowedFileExtensions: null, | 
|         defaultPreviewContent: null, | 
|         customLayoutTags: {}, | 
|         customPreviewTags: {}, | 
|         previewSettings: defaultPreviewSettings, | 
|         fileTypeSettings: defaultFileTypeSettings, | 
|         previewFileIcon: '<i class="glyphicon glyphicon-file"></i>', | 
|         previewFileIconClass: 'file-other-icon', | 
|         previewFileIconSettings: {}, | 
|         previewFileExtSettings: {}, | 
|         buttonLabelClass: 'hidden-xs', | 
|         browseIcon: '<i class="glyphicon glyphicon-folder-open"></i> ', | 
|         browseClass: 'btn btn-primary', | 
|         removeIcon: '<i class="glyphicon glyphicon-trash"></i>', | 
|         removeClass: 'btn btn-default', | 
|         cancelIcon: '<i class="glyphicon glyphicon-ban-circle"></i>', | 
|         cancelClass: 'btn btn-default', | 
|         uploadIcon: '<i class="glyphicon glyphicon-upload"></i>', | 
|         uploadClass: 'btn btn-default', | 
|         uploadUrl: null, | 
|         uploadAsync: true, | 
|         uploadExtraData: {}, | 
|         zoomModalHeight: 480, | 
|         minImageWidth: null, | 
|         minImageHeight: null, | 
|         maxImageWidth: null, | 
|         maxImageHeight: null, | 
|         resizeImage: false, | 
|         resizePreference: 'width', | 
|         resizeQuality: 0.92, | 
|         resizeDefaultImageType: 'image/jpeg', | 
|         minFileSize: 0, | 
|         maxFileSize: 0, | 
|         maxFilePreviewSize: 25600, // 25 MB | 
|         minFileCount: 0, | 
|         maxFileCount: 0, | 
|         validateInitialCount: false, | 
|         msgValidationErrorClass: 'text-danger', | 
|         msgValidationErrorIcon: '<i class="glyphicon glyphicon-exclamation-sign"></i> ', | 
|         msgErrorClass: 'file-error-message', | 
|         progressThumbClass: "progress-bar progress-bar-success progress-bar-striped active", | 
|         progressClass: "progress-bar progress-bar-success progress-bar-striped active", | 
|         progressCompleteClass: "progress-bar progress-bar-success", | 
|         progressErrorClass: "progress-bar progress-bar-danger", | 
|         progressUploadThreshold: 99, | 
|         previewFileType: 'image', | 
|         elCaptionContainer: null, | 
|         elCaptionText: null, | 
|         elPreviewContainer: null, | 
|         elPreviewImage: null, | 
|         elPreviewStatus: null, | 
|         elErrorContainer: null, | 
|         errorCloseButton: '<span class="close kv-error-close">×</span>', | 
|         slugCallback: null, | 
|         dropZoneEnabled: true, | 
|         dropZoneTitleClass: 'file-drop-zone-title', | 
|         fileActionSettings: {}, | 
|         otherActionButtons: '', | 
|         textEncoding: 'UTF-8', | 
|         ajaxSettings: {}, | 
|         ajaxDeleteSettings: {}, | 
|         showAjaxErrorDetails: true | 
|     }; | 
|   | 
|     $.fn.fileinputLocales.en = { | 
|         fileSingle: 'file', | 
|         filePlural: 'files', | 
|         browseLabel: 'Browse …', | 
|         removeLabel: 'Remove', | 
|         removeTitle: 'Clear selected files', | 
|         cancelLabel: 'Cancel', | 
|         cancelTitle: 'Abort ongoing upload', | 
|         uploadLabel: 'Upload', | 
|         uploadTitle: 'Upload selected files', | 
|         msgNo: 'No', | 
|         msgNoFilesSelected: 'No files selected', | 
|         msgCancelled: 'Cancelled', | 
|         msgZoomModalHeading: 'Detailed Preview', | 
|         msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', | 
|         msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>.', | 
|         msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload.', | 
|         msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>.', | 
|         msgFileNotFound: 'File "{name}" not found!', | 
|         msgFileSecured: 'Security restrictions prevent reading the file "{name}".', | 
|         msgFileNotReadable: 'File "{name}" is not readable.', | 
|         msgFilePreviewAborted: 'File preview aborted for "{name}".', | 
|         msgFilePreviewError: 'An error occurred while reading the file "{name}".', | 
|         msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', | 
|         msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.', | 
|         msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.', | 
|         msgUploadAborted: 'The file upload was aborted', | 
|         msgUploadThreshold: 'Processing...', | 
|         msgValidationError: 'Validation Error', | 
|         msgLoading: 'Loading file {index} of {files} …', | 
|         msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.', | 
|         msgSelected: '{n} {files} selected', | 
|         msgFoldersNotAllowed: 'Drag & drop files only! {n} folder(s) dropped were skipped.', | 
|         msgImageWidthSmall: 'Width of image file "{name}" must be at least {size} px.', | 
|         msgImageHeightSmall: 'Height of image file "{name}" must be at least {size} px.', | 
|         msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.', | 
|         msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.', | 
|         msgImageResizeError: 'Could not get the image dimensions to resize.', | 
|         msgImageResizeException: 'Error while resizing the image.<pre>{errors}</pre>', | 
|         dropZoneTitle: 'Drag & drop files here …', | 
|         dropZoneClickTitle: '<br>(or click to select {files})', | 
|         previewZoomButtonTitles: { | 
|             prev: 'View previous file', | 
|             next: 'View next file', | 
|             toggleheader: 'Toggle header', | 
|             fullscreen: 'Toggle full screen', | 
|             borderless: 'Toggle borderless mode', | 
|             close: 'Close detailed preview' | 
|         } | 
|     }; | 
|   | 
|     $.fn.fileinput.Constructor = FileInput; | 
|   | 
|     /** | 
|      * Convert automatically file inputs with class 'file' into a bootstrap fileinput control. | 
|      */ | 
|     $(document).ready(function () { | 
|         var $input = $('input.file[type=file]'); | 
|         if ($input.length) { | 
|             $input.fileinput(); | 
|         } | 
|     }); | 
| })); |